前言
一直以來都有去通過blog去了解一下技術(shù)的問題,但是因?yàn)閎log畢竟是別人消化的東西,在作者閱讀相關(guān)資料 -> 消化 -> blog文字輸出 -> 自己讀blog -> 自己消化,這是一個(gè)很長的信息鏈,而這個(gè)鏈接每一個(gè)環(huán)節(jié)都存在信息漏斗,到最終到自己消化的時(shí)候,可能和信息最初的樣子,會(huì)有比較大的偏差了。
還有另外一個(gè)問題就是,讀取別人的blog,自己沒有親身實(shí)踐過,看的時(shí)候理解了,但是總是不深刻,到后面遇到這個(gè)知識點(diǎn)的時(shí)候,需要比較長的時(shí)間去慢慢回憶起來,組合成一個(gè)大概的信息具象,沒有一個(gè)系統(tǒng)的了解。
高中的時(shí)候,數(shù)學(xué)老師一直在強(qiáng)調(diào)好記性不如爛筆頭,一直叫我們就算看懂了,你寫下來之后理解會(huì)加深,現(xiàn)在深有體會(huì)?,F(xiàn)在不是好記性不如爛筆頭,像我這種記性不好的,需要爛鍵盤的??!
所以,在以后的工作還是需要作出一點(diǎn)點(diǎn)改變,看到需要不理解的知識點(diǎn),是需要從信息的根來源進(jìn)行尋根問題,并且記下來用文字表達(dá)一次,才能對相關(guān)知識點(diǎn)有一個(gè)系統(tǒng)行的理解。
吃過的虧,要接受教訓(xùn)??!
所以這篇文章是在理解property,是從runtime和CoreFoundation出發(fā)去理解,理解其原理,能有更深刻的理解。
runtime的getter實(shí)現(xiàn)
在很多書籍或者blog里面,都有解析到Objective-C中各個(gè)修飾屬性的區(qū)別,因?yàn)槎际且粋€(gè)結(jié)論給出,并沒有理解里面的具體實(shí)現(xiàn),所以并不深刻。所以,在runtime層面查看對象屬性賦值的實(shí)現(xiàn)。
在runtime的源代碼中,在Private Header下的objc_abi.h文件中,可以找到對象屬性讀寫的abi定義,而實(shí)際的實(shí)現(xiàn)代碼存放在objc-accessors.mm文件中。由于這是私有abi,在iOS的SDK里面的/usr/include/目錄下并不能看到這些信息。如果需要查看這個(gè)定義,需要在runtime的源代碼才能看到。
在這個(gè)objc-accessors.mm文件中,先看getter方法對應(yīng)的實(shí)現(xiàn):
//getter函數(shù)參數(shù)與定義的修飾詞相關(guān)的就只有atomic修飾詞
//也就是說除了atomic修飾詞和nonatomic修飾詞,copy、assign、strong、weak修飾詞都并無相關(guān)
id objc_getProperty(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) {
if (offset == 0) {
return object_getClass(self);
}
// Retain release world
id *slot = (id*) ((char*)self + offset);//計(jì)算屬性所在的指針偏移量
if (!atomic) return *slot;//如果是非原子性操作,直接返回屬性的對象指針
//原子性操作,則繼續(xù)執(zhí)行
//獲取屬性鎖,屬性鎖的定義是這樣的
//PropertyLocks是一個(gè)StripedMap<spinlock_t>類型的全局變量
//而StripedMap是一個(gè)用數(shù)組來實(shí)現(xiàn)的hashmap,key是指針,value是類型是spinlock_t對象
//而spinlock_t則是mutex_tt<LOCKDEBUG>的類,而mutex_tt類內(nèi)部是由os_unfair_lock mLock來實(shí)現(xiàn)
//一言以蔽之,PropertyLocks[slot]目的就是獲取os_unfair_lock對象
spinlock_t& slotlock = PropertyLocks[slot];
slotlock.lock();//加鎖
id value = objc_retain(*slot);//獲取到的對象引用計(jì)數(shù)+1
slotlock.unlock();//解鎖
// for performance, we (safely) issue the autorelease OUTSIDE of the spinlock.
//將獲取到的對象注冊到自動(dòng)釋放池中,保證值能一定獲取到,所以是線程安全的
return objc_autoreleaseReturnValue(value);
}
從函數(shù)名上就很清晰的看出來屬性修飾詞對應(yīng)的方法,而且就是標(biāo)準(zhǔn)的objc中函數(shù)調(diào)用時(shí),使用objc_msgSend函數(shù)進(jìn)行函數(shù)調(diào)用的函數(shù)格式。前面兩個(gè)是隱含參數(shù)id和_cmd,后面是函數(shù)的實(shí)際參數(shù)。
通過上述解析,那么可以總結(jié)一下getter的特性了:
- getter獲取屬性值,copy、assign、strong、weak修飾詞無相關(guān),只與atomic和nonatomic修飾詞有關(guān)
- 使用nonatomic修飾詞,獲取到屬性值后立馬返回,效率高
- 使用atomic修飾的屬性,獲取過程會(huì)有加鎖解鎖過程,會(huì)有性能的損耗
- 使用atomic修飾的屬性,會(huì)將對象注冊到自動(dòng)釋放池中
這就是runtime環(huán)境中g(shù)etter的是整個(gè)過程,相對于setter來說,比較簡單。
最后的最后
上面的分析是基于屬性賦值的猜測,在objc源代碼的全局并沒有搜索到objc_getProperty函數(shù)的調(diào)用方。在runtime中,所有的函數(shù)調(diào)用都是通過objc_msgSend函數(shù)來進(jìn)行調(diào)用的,通過selector方法選擇器來獲取真正的IMP函數(shù)指針來執(zhí)行最終的實(shí)現(xiàn)。而在objc源代碼中,貌似沒有找到IMP的定義,所以以上的分析都是基于猜測的。
今天終于將iMac降級了,能拋棄objc源代碼的工程,但是寫debug代碼后在objc_getProperty打了斷點(diǎn),發(fā)現(xiàn)并沒有調(diào)用到objc_getProperty函數(shù),這就很困惑了。因?yàn)樵谡{(diào)用Foundation層的setter方法,并沒有具體的賦值實(shí)現(xiàn)的。困惑。。。