1. 程式人生 > >由category為什麼不能新增屬性所想到的

由category為什麼不能新增屬性所想到的

在category裡新增屬性的情況?

在類中使用@property,系統會自動生成帶“_”的成員變數和該變數的setter和getter方法。也就是說,屬性相當於一個成員變數加getter和setter方法

在分類裡使用@property宣告屬性,只是將該屬性新增到該類的屬性列表,但是沒有生成相應的成員變數,也沒有實現setter和getter方法。

這篇博文將的很詳細 :
點我

不足之處還是沒有講出類別不能新增屬性的根本原因。

那麼根本原因又是什麼呢?

category 它是在執行期決議的。 因為在執行期即編譯完成後,物件的記憶體佈局已經確定,如果新增例項變數就會破壞類的內部佈局,這對編譯型語言來說是災難性的。

為什麼使用Runtime又可以新增屬性?

使用Runtime技術中的關聯物件可以為類別新增屬性。

其原因是:關聯物件都由AssociationsManager管理,AssociationsManager裡面是由一個靜態AssociationsHashMap來儲存所有的關聯物件的。這相當於把所有物件的關聯物件都存在一個全域性map裡面。而map的的key是這個物件的指標地址(任意兩個不同物件的指標地址一定是不同的),而這個map的value又是另外一個AssociationsHashMap,裡面儲存了關聯物件的kv對。

如合清理關聯物件?

runtime的銷燬物件函式objc_destructInstance裡面會判斷這個物件有沒有關聯物件,如果有,會呼叫_object_remove_assocations做關聯物件的清理工作。(詳見Runtime的原始碼)

這裡說一下category和extension的區別?

extension看起來很像一個匿名的category,但是extension和有名字的category幾乎完全是兩個東西。 extension在編譯期決議,它就是類的一部分,在編譯期和標頭檔案裡的@interface以及實現檔案裡的@implement一起形成一個完整的類,它伴隨類的產生而產生,亦隨之一起消亡。extension一般用來隱藏類的私有資訊,你必須有一個類的原始碼才能為一個類新增extension,所以你無法為系統的類比如NSString新增extension。(詳見2)

但是category則完全不一樣,它是在執行期決議的。
就category和extension的區別來看,我們可以推匯出一個明顯的事實,extension可以新增例項變數,而category是無法新增例項變數的(因為在執行期,物件的記憶體佈局已經確定,如果新增例項變數就會破壞類的內部佈局,這對編譯型語言來說是災難性的)。

參考博文:美團點評技術團隊 這篇文章非常好,建議大家都看一下。