成員變量與屬性

寫完類與對象后,我們今天來講講成員變量和屬性。

1.類型編碼

? ? ? ?編譯器將每個方法的返回值和參數(shù)類型編碼為一個字符串,并將其與方法的selector關(guān)聯(lián)在一起。當(dāng)給定一個類型時,@encode返回這個類型的字符串編碼。這些類型可以是諸如int、指針這樣的基本類型,也可以是結(jié)構(gòu)體、類等類型。事實上,任何可以作為sizeof()操作參數(shù)的類型都可以用于@encode()。對于屬性而言,還會有一些特殊的類型編碼,以表明屬性是只讀、拷貝、retain等等。(原文出自這里)

2.成員變量

打開runtime.h,我們一點都不驚訝地發(fā)現(xiàn)成員變量實際上是一個指向objc_ivar的指針。

繼續(xù)跟蹤objc_ivar,找到如下定義

故名思義,ivar_name就是成員變量的名稱,ivar_type就是類型,offset就是離基地址的偏移量。至于space是什么我不太清楚,猜測應(yīng)該是為兼容架構(gòu)而產(chǎn)生的變量。

3.屬性

objc_property_t:聲明的屬性的類型,是一個指向objc_property結(jié)構(gòu)體的指針。

屬性的定義

property_getAttributes函數(shù)返回objc_property_attribute_t結(jié)構(gòu)體列表,objc_property_attribute_t結(jié)構(gòu)體包含name和value。下面的截圖是一些關(guān)于屬性和成員變量的操作,大同小異。

屬性和成員變量的操作

4.存取器

對于一個屬性來說,我們既可以直接訪問實例變量,也可以通過存取器間接訪問。那什么時候直接訪問,什么時候間接訪問。我這里列舉了一些使用存取器的情況。

?(1)鍵值觀察。存取器會自動調(diào)用willChangeValueForKey:和didChangeValueForKey:。如果直接訪問實例變量,會導(dǎo)致監(jiān)聽者收不到回調(diào)。

?(2)副作用。開發(fā)者在自身或者某個子類會在set方法中引入副作用??赡苁前l(fā)出通知火災(zāi)NSUndoManager中注冊了事件。同時,開發(fā)者或者子類會在get方法中增加緩存,而直接訪問實例變量會繞開緩存。

(3)惰性初始化。不用存取器的話,不會被初始化。

以下情況則是需要直接訪問實例變量:

(1)存取器內(nèi)部。有可能導(dǎo)致死循環(huán)。

(2)dealloc。這里使用存取器訪問的話有可能導(dǎo)致監(jiān)聽者收到不必要的通知。

(3)初始化。類似dealloc。這里通常只初始化readonly對象。

5.健壯的實例變量

由于我有一份ppt,這里就直接上ppt截圖,不一一講了。


6.一些疑問

有時候我們看到這樣的一個方法:class_addIvar(<#__unsafe_unretained Class cls#>, <#const char *name#>, <#size_t size#>, <#uint8_t alignment#>, <#const char *types#>),這個方法顯然是向一個類中添加成員變量,但是僅僅是能向一個動態(tài)創(chuàng)建的類中添加成員變量,而編譯好的類是不能再通過這個方法添加了。動態(tài)添加成員變量的時候,我們必須為它指定內(nèi)存管理策略,在這個方面里面卻看不見類似的參數(shù),那究竟該怎么做呢?詳情請看這里

好了,寫完收工。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容