在Objective-C中晦攒,幾乎所有的類都是NSObject的子類狐肢,另一部分都是NSProxy的子類弃秆。
在Foundation框架下,NSObject和NSProxy兩個基類定義了類層次結(jié)構(gòu)中該類下方所有類的公共接口和行為入桂。NSProxy是專門用于實現(xiàn)代理的類奄薇。這兩個類都遵循了NSObject協(xié)議。在NSObject協(xié)議中事格,聲明了所有OC對象的公共方法。
先從結(jié)構(gòu)定義上來看
這里是NSObject的一些定義搞隐,直接在編譯器里面commend點進NSObject就可以看到,雖然有一些是標注適用Objc2.0之前驹愚。但是并不是代表之后就不存在這些參數(shù)了,只是在結(jié)構(gòu)上進一步的進行了封裝劣纲。里面有一句“ Class instead of struct objc_class *”,所以我們可以再去找找有關(guān)objc_class的源碼逢捺。
這里看到objc_class 是繼承自objc_object
從上可以看出,我們平時用的id類型癞季,其實就是一個objc_object對象劫瞳,這也是為什么id類型可以指向任何對象的原因。
然后objc_class是繼承自objc_object的绷柒,這表明其實類本質(zhì)也是一個對象志于。
這里要引入一個問題我們在調(diào)用實例方法的時候,通過類的實例對象來進行調(diào)用废睦。那調(diào)用類方法的時候伺绽,又是調(diào)用誰的實例呢?
先看看實例方法是如何別調(diào)用的嗜湃,當對象的實例方法被調(diào)用奈应,是通過isa來找到對應(yīng)的類,然后在該類的class_data_bits_t中去查找方法购披。class_data_bits_t是指向了類對象的數(shù)據(jù)區(qū)域杖挣。在該數(shù)據(jù)區(qū)域內(nèi)查找相應(yīng)方法的對應(yīng)實現(xiàn)。
對于類對象則是引入了一個元類的概念(meta-class)刚陡。
類對象的類方法調(diào)用時惩妇,通過類的 isa 在元類中獲取方法的實現(xiàn)株汉。它存儲著一個類的所有類方法。每個類都會有一個單獨的meta-class屿附,因為每個類的類方法基本不可能完全相同郎逃。
額外提兩點,第一點是在運行的時候挺份,實例是可以創(chuàng)建無數(shù)個的褒翰,但是類對象和元類對象卻是唯一的。類對象和元類對象會在main方法執(zhí)行之前就被創(chuàng)建出來匀泊。所以在工作的過程中對于廢棄了的類盡量就直接移除掉优训。這樣可以避免一些不必要的損耗。
第二點是對象的方法并沒有存儲于對象的結(jié)構(gòu)體中各聘,這個其實也比較合理揣非,如果每創(chuàng)建一個都要把相同的方法復(fù)制一遍,這樣對內(nèi)存太不友好了躲因。所以在實例方法被調(diào)用時早敬,它要通過自己持有的 isa 來查找對應(yīng)的類,然后在這里的 class_data_bits_t 結(jié)構(gòu)體中查找對應(yīng)方法的實現(xiàn)大脉。同時搞监,每一個 objc_class 也有一個指向自己的父類的指針 super_class 用來查找繼承的方法。
當實例方法被調(diào)用時镰矿,它要通過自己持有的 isa 來查找對應(yīng)的類
從網(wǎng)上找了一張NSObject的類圖
這個就是現(xiàn)在的結(jié)構(gòu)圖
接下來具體介紹一下
cache_t cache
class_data_bits_t bits
cache_t cache的源碼
這里面包含了一個bucket_t的結(jié)構(gòu)體和兩個mask_t參數(shù)
分別看看對應(yīng)的源碼
關(guān)于_mask和_occupied查資料是說
_mask:分配用來緩存bucket的總數(shù)琐驴。
_occupied:表明目前實際占用的緩存bucket的個數(shù)。
bucket_t的結(jié)構(gòu)體中存儲了一個參數(shù)與一個函數(shù)指針秤标,這個函數(shù)指針是指向一個具體的方法實現(xiàn)绝淡。
cache的作用主要是用來緩存常用的方法,當一個方法被調(diào)用的時候苍姜,會優(yōu)先在cache中查找牢酵,如果沒找到再去methodLists中查找。
class_data_bits_t
對于這個衙猪,源碼里面有一句注釋 // class_rw_t * plus custom rr/alloc flags
相當于 class_rw_t指針加上 rr/alloc 的標志茁帽。
Objc的類的屬性、方法屈嗤、以及遵循的協(xié)議在obj 2.0的版本之后都放在class_rw_t中潘拨。class_ro_t是一個指向常量的指針,存儲來編譯器決定了的屬性饶号、方法和遵守協(xié)議铁追。