Objective C的對象模型
絕大多數(shù)對象繼承自NSObject,NSObject就是一個包含isa指針的結(jié)構(gòu)體次舌,
每一個id類型就是一個結(jié)構(gòu)體,可以從下圖看出
我們再看objc_class是什么彼念,
可以看出objc_class也是一個包含isa(Class類型)的指針的結(jié)構(gòu)體浅萧,并且從兼容objc1.0的代碼中可以看出來哲思,objc_class還包含了一系列的信息,比如objc_method_list(方法列表)帝簇,objc_ivar_list(成員變量列表)靠益,super_class(父類)
梳理一下,NSObject是一個包含Class指針的對象胧后,Class指針就是結(jié)構(gòu)體objc_class,然后objc_class結(jié)構(gòu)體的結(jié)構(gòu)如上圖所示纸巷。
因為Class就是objc_class,所以我們可以看出來瘤旨,每一個objc_class實際上也指向了另一個objc_class竖伯。
所以所有的對象都有一個isa實例變量,包含了這個對象的所有信息黔夭,比如objc_method_list(方法列表)羽嫡,objc_ivar_list(成員變量列表),super_class(父類)婚惫,
isa是一個指針,指向了該對象的類.實質(zhì)上,同一個類的實例,都指向同一個類對象(類也是一種特殊對象惜索,objc_class).類中包含了實例方法,也就是說,同一個類的所有實例共用了這些實例方法.消息就是發(fā)送給對象,對象轉(zhuǎn)交給其isa指向類去處理.
Objective-C的這種設計,既可以友好地實現(xiàn)面向?qū)ο?又可以有效地節(jié)約內(nèi)存.降低冗余數(shù)據(jù).對象對方法的調(diào)用是通過isa間接去調(diào)用,這樣就造成了方法調(diào)用的動態(tài)性,主要原因是:
一個對象并不曉得它能否應答一個方法,它本身既不包含方法的實現(xiàn),也不包含有方法的指針,而是間接通過isa轉(zhuǎn)到自己的類才能知道
類中的實例方法是以鏈表形式存在,運行時候,可以修改鏈表中的實例方法,
(category就是這么實現(xiàn)的箕昭,在方法鏈表里面添加函數(shù))
好绍傲,現(xiàn)在我們再梳理一下惠险,事實上捺球,當我們創(chuàng)建一個通常我們認為的對象的時候,實際上是在堆中申請了空間來存儲對象的實例變量氮兵,那么對象的實例方法方法在哪兒呢?對象將如何來相應消息呢卜高?
上文說了南片,每一個對象都有一個isa指針(objc_class,即類對象)铃绒,這個指針里面包含了所有的實例方法,那還有類方法呢矮燎?類對象也有一個isa指針赔癌,指向元類,元類就包含了類方法灾票。
可以看看這個圖(下面也有),虛線代表isa的指向既们,實線代表superclass的指向
元類(metaclass)也是一個對象正什,那么元類的isa指針又指向哪里呢?為了設計上的完整婴氮,所有的元類的isa指針都會指向一個根元類(root meta class)。所以可以把root meta class視作一個空的荣暮,沒有額外定義的類。
該圖中穗酥,最讓人困惑的莫過于Root Class了。在實現(xiàn)中迷扇,Root Class是指NSObject,我們可以從圖中看出:
NSObject類包括它的對象實例方法器一。
NSObject的元類包括它的類方法厨内,例如alloc方法。
NSObject的元類繼承自NSObject類雏胃。
一個NSObject的類中的方法同時也會被NSObject的子類在查找方法時找到。
我們可以看出root class(即NSObject)有isa的指向方仿,但是superclass的指向卻是空的统翩,所以不會循環(huán)
因為對象在內(nèi)存中的排布可以看成一個結(jié)構(gòu)體,該結(jié)構(gòu)體的大小并不能動態(tài)變化委粉。所以無法在運行時動態(tài)給對象增加成員變量娶桦。
相對的,對象的方法定義都保存在類的可變區(qū)域中衷畦。Objective-C 2.0并未在頭文件中將實現(xiàn)暴露出來,但在Objective-C 1.0中斤程,我們可以看到方法的定義列表是一個名為methodLists的指針的指針(如下圖所示)铛嘱。通過修改該指針指向的指針的值袭厂,就可以實現(xiàn)動態(tài)地為某一個類增加成員方法墨吓。這也是Category實現(xiàn)的原理纹磺。同時也說明了為什么Category只可為對象增加成員方法,卻不能增加成員變量秘症。