12

在Objective-C中是否有任何反射手段可以讓您通過檢查對象的公共屬性並生成encodeWithCoder:和initWithCoder:的通用實現來編寫通用的NSCoding實現。通用的NSCoding實現的Objective-C反射

我正在考慮類似於XStream的Java,它允許使用反射來對Java對象進行序列化和反序列化。更好的做法可能是將屬性標記爲你想要序列化的東西或者是暫時的(比如Java中的transient關鍵字)。

我一直在閱讀有關Cocoa Archives and Serializations Programming Guide的文檔。我知道你需要對你的對象的序列化進行一些控制,但是它通常是一個對稱的過程,並且爲了反序列化它而需要將序列化的代碼進行反編譯似乎很奇怪。我是乾的信徒(不要重複自己)。

回答

12

這不僅是可能的,但我有一個朋友被刺傷了。 (您可以看到他的blog about it here。)使用Objective-C 2.0 Runtime Reference中記錄的Objective-C運行時功能完成反射。看一看。

但是,請注意,只有當您希望保存所有實例變量的通用行爲時,這纔會起作用。不過,您可能不希望NSView保存其超級視圖;在這種情況下,通用情況將不起作用。

通過爲要保存的任何實例變量聲明屬性並保留任何其他變量爲「隱藏」,您可以區分事物序列化和事物不序列化,但這是扭曲屬性的整體目的收益不大。我不會推薦它。

6

(我是博客文章的作者,鏈接到BJ荷馬的評論)。有幾個使用代碼的注意事項:

  1. 目標類必須符合KVC。如果你爲你的ivars使用Objective-C 2.0屬性,那麼你就全部設置好了。否則,您需要確保您的類設置爲正確響應valueForKey:和setValue:forKey:方法。
  2. 該代碼使用運行時的未記錄「特徵」遞歸地將伊娃類別符合NSCoding。編譯時,幾乎所有的打字信息(AFAIK)都從代碼中刪除,但爲了保存ivars,也必須符合NSCoding。我發現,如果ivar是一個對象,並且我調用它的ivar_getTypeEncoding(),則會返回一個類似於以下內容的c字符串:{#IVAR_CLASS}(示例:{#NSString})。我所做的是獲取#和}之間的字符串,使用NSClassFromString創建一個Class對象,並對其進行遞歸。
  3. 此代碼將保存所有的ivars。在您自己的風險(當然)
  4. 使用

我寫這主要是作爲一個概念證明,並有在該代碼會失敗壯觀許多實例。例如,在對象A中有一個用於B的ivar,並且B有一個用於A的ivar,那麼使用該代碼序列化一個或另一個會(我相信)會導致無限循環。儘管如此,我認爲Objective-C甚至可以讓你像第一個那樣做東西,這真是太令人震驚了。