iOS 序列化與反序列化 runtime 02

2021-08-03 22:21:33 字數 3242 閱讀 3930

觀察上面的initwithcoder**我們可以發現,序列化與反序列化中最重要的環節是遍歷類的變數,保證不能遺漏。

這裡需要特別注意的是:

編譯碼的範圍不能僅僅是自身類的變數,還應當把除nsobject類外的所有層級父類的屬性變數也進行編譯碼!

由此可見,這幾乎是個純體力活。而runtime在遍歷變數這件事情上能為我們提供什麼幫助呢?我們可以通過runtime在執行時獲取自身類的所有變數進行編譯碼;然後對父類進行遞迴,獲取除nsobject外每個層級父類的屬性(非私有變數),進行編譯碼。

runtime中獲取某類的所有變數(屬性變數以及例項變數)api:

ivar *class_copyivarlist

(class cls, unsigned

int *outcount)

獲取某類的所有屬性變數api:

objc_property_t *class_copypropertylist(class cls, unsigned

int *outcount)

runtime的所有開放api都放在objc/runtime.h裡面。上面的一些資料型別有些同學可能沒見過,這裡我們先簡單地介紹一下,更詳細的介紹請自行查閱其他資料,強烈建議開啟

ivar是runtime對於變數的定義,本質是乙個結構體:

struct objc_ivar  

typedef

struct objc_ivar *ivar;

因此在上面**的基礎上我們我們需要注意一下細節,設乙個指標,先指向本身類,處理完指向superclass,處理完再指向superclass的superclass...。**如下(這裡僅以encodewithcoder:為例,畢竟initwithcoder:同理):

- (void)encodewithcoder:(nscoder *)coder

}

free(ivarlist);

cls = class_getsuperclass(cls); //指標指向當前類的父類

}

}

這樣真的結束了嗎?不是的。當你的跑上面的**時程式有可能會crash掉,crash的地方在[self valueforkey:key]這一句上。原來是這裡的kvc無法獲取到父類的私有變數(即例項變數)。因此,在處理到父類時不能簡單粗暴地使用class_copyivarlist,而只能取父類的屬性變數。這時候3.2節部分的class_copypropertylist就派上用場了。在處理父類時用後者代替前者。

2016.0804補充

在最近的ios中列印propertylist會發現有superclassdescriptiondebugdescriptionhash等四個屬性。對這幾個屬性進行encode操作會導致crash。因此在encode前需要遮蔽掉這些key

於是最終的**(額~其實還不算最終):

- (id)initwithcoder:(nscoder *)coder    

}

free(ivarlist);

free(proplist);

cls = class_getsuperclass(cls);

}

return

self;

}

- (void)encodewithcoder:(nscoder *)coder

}

free(ivarlist);

free(proplist);

cls = class_getsuperclass(cls);

}

}

在邏輯上,上面的**應該是目前為止比較完美的自動序列化與反序列解決方案了。即使某個類的繼承深度極其深,變數極其多,序列化的**也就以上這些。但是我們回到文章第二節提出的幾點場景假設,其中有一點提到:

若你的工程中有很多像person的自定義類需要做序列化操作呢?

如果是在以上場景下,每個model類都需要寫一次上面的**。這在一定程度上也造成冗餘了。同時,你也會覺得這篇文章的標題就是瞎扯淡,根本就不是一行**的事。上面的**冗餘,我這種對**有很強潔癖的程式旺是萬萬接受不了的。那就再封裝一層!這裡我採用巨集的方式將上述**濃縮成一行,放到乙個叫wzlserializekit.h的標頭檔案中:

#define wzlserialize_coder_decoder()     \

\- (id)initwithcoder:(nscoder *)coder \

\} \

free(ivarlist); \

free(proplist); \

cls = class_getsuperclass(cls); \

} \

return

self; \

} \

\- (void)encodewithcoder:(nscoder *)coder \

\} \

free(ivarlist); \

free(proplist); \

cls = class_getsuperclass(cls); \

} \

}

之後需要序列化的地方只要兩步:

1、import "wzlserializekit.h"

2、呼叫wzlserialize_coder_decoder();即可。兩個字:清爽。

此外,copywithzone中同樣可以用相同的原理對變數進行自動化copy。同樣地,我們也可以用乙個巨集封裝掉copywithzone方法。這裡就不再贅述。

值得一提的是,以上**我已經放到我的github中,並且提供了cocoapods支援。使用的時候只需要pod `wzlserializekit`。點 此處 跳轉到我的github.

謝謝!!!

IOS 序列化與反序列化

1到底這個序列化有啥作用?物件導向的程式在執行的時候會建立乙個複雜的物件圖,經常要以二進位制的方法序列化這個物件圖,這個過程叫做archiving.二進位製流可以通過網路或寫入檔案中 於某教材的一段話 本人的理解是當你於寫資料需要本地儲存時,即將你的資料寫到硬碟上的時候,你就必須對他進行序列化,轉換...

iOS 序列化 與 反序列化

主要記住兩個過程和呼叫的方法 反序列化 json oc物件 jsonobjectwithdata 序列化 oc物件 json datawithjsonobject 以上兩個方法均為 nsjsonserialization 的類方法 viewcontroller.m 0715 03json解析 01 ...

序列化和反序列化 C 序列化與反序列化。

序列化介紹 把物件用一種新的格式來表示。系列化只序列化資料。序列化不建議使用自動屬性 為什麼要序列化 將乙個複雜的物件轉換流,方便儲存與資訊交換。class program class person public int age 二進位制序列化 就是將物件變成流的過程,把物件變成byte class...