每個(gè)objc對(duì)象內(nèi)都有這幾部分:1.對(duì)象方法list 2.成員變量list 3.屬性list 4.isa指針
首先父能,對(duì)象方法list runtime使用objc_msgSend(receiver, selector)對(duì)方法進(jìn)行調(diào)用 receiver是方法的調(diào)用者, selector則是方法 @selector其實(shí)是方法名 在調(diào)用方法時(shí)在receiver中的method list中找到該方法然后再找到它的IMP(實(shí)現(xiàn))捻脖,如果找不到的話這就會(huì)發(fā)生unrecognized selector而導(dǎo)致crash。當(dāng)然這時(shí)候也還有補(bǔ)救措施,這就是傳說(shuō)中的消息轉(zhuǎn)發(fā)。首先第一次是在+resolveInstanceMethod:或者 +resolveClassMethod: 在這里我們可以添加一個(gè)函數(shù)調(diào)用纸型,然后返回yes這樣安全了。如果沒有就進(jìn)行fast forwarding實(shí)現(xiàn)-forwardingTargetForSelector:方法進(jìn)行對(duì)象轉(zhuǎn)移梅忌,也就是改變方法的調(diào)用者绊袋。如果還沒有調(diào)用就-methodSignatureForSelector:通過這個(gè)函數(shù)進(jìn)行獲得參數(shù),在這里進(jìn)行簽名NSInvocation并發(fā)送-forwardInvocation:铸鹰,否則就會(huì)造成crash。對(duì)象方法列表存放在類對(duì)象中皂岔。
16.09.14補(bǔ)充
id objc_msgSend(id self, SEL op, ...) {
if?(!self)?return?nil;
IMP?imp?=?class_getMethodImplementation(self->isa,?SEL?op);
imp(self,?op,?...);?//調(diào)用這個(gè)函數(shù)蹋笼,偽代碼...
}
//查找IMP
IMP?class_getMethodImplementation(Class?cls,?SEL?sel)?{
if?(!cls?||?!sel)?return?nil;
IMP?imp?=?lookUpImpOrNil(cls,?sel);
if?(!imp)?return?_objc_msgForward;?//_objc_msgForward?用于消息轉(zhuǎn)發(fā)
return?imp;
}
IMP?lookUpImpOrNil(Class?cls,?SEL?sel)?{
if?(!cls->initialize())?{
_class_initialize(cls);
}
Class?curClass?=?cls;
IMP?imp?=?nil;
do?{?//先查緩存,緩存沒有時(shí)重建,仍舊沒有則向父類查詢
if?(!curClass)?break;
if?(!curClass->cache)?fill_cache(cls,?curClass);
imp?=?cache_getImp(curClass,?sel);
if?(imp)?break;
}?while?(curClass?=?curClass->superclass);
return?imp;
}
下一個(gè)就是成員變量list 我們一般申明變量的時(shí)候在前面加_,比如_var。在成員變量list中存放當(dāng)前類的實(shí)例變量以及所有父類的實(shí)例變量剖毯。
然后是屬性list 申明屬性用@property 一般來(lái)說(shuō)property=ivar+setter+getter圾笨。在申明屬性后,編譯器會(huì)自動(dòng)訪問這些屬性所需方法逊谋,這就是autosynthesis擂达。這是在編譯器進(jìn)行,所以編譯器里看不見代碼胶滋。假如我們要更改setter板鬓,getter的名字,就在申明時(shí)在填充如@property(getter=???,setter=set???)這樣就可以更改默認(rèn)的生成方法究恤。假如我們要更改默認(rèn)生成的成員變量名字就采用@synthesize俭令,如@synthesize darling = _myDarling。同時(shí)還有一個(gè)@dynamic部宿,它會(huì)告訴編譯器setter getter用戶自己實(shí)現(xiàn)抄腔,如果沒有實(shí)現(xiàn)這兩個(gè)方法時(shí)正常編譯是沒問題,就是在使用這個(gè)變量時(shí)就會(huì)crash理张。
isa指針在第一次看挺玄學(xué)的赫蛇,經(jīng)常看見但不太了解什么作用雾叭。先放一張圖悟耘。
眾所周知,每個(gè)類在調(diào)用之前會(huì)生成一個(gè)靜態(tài)對(duì)象拷况。一個(gè)類存放著它的superclass指針指向父類作煌,而isa指針 對(duì)象指向類對(duì)象 類對(duì)象的isa指針指向元對(duì)象,元對(duì)象的isa指針指向根元對(duì)象根類對(duì)象的superclass指向nil赚瘦,根對(duì)象在objc中為nsobject粟誓。在調(diào)用一個(gè)方法時(shí),通過isa指針找到對(duì)象所屬的類起意,然后通過類的方法列表以及其父類的方法列表找尋方法進(jìn)行調(diào)用鹰服,在進(jìn)行objc_msgSend時(shí)并沒有返回值,返回值都是具體的調(diào)用產(chǎn)生的揽咕,所以objc可以對(duì)nil進(jìn)行方法調(diào)用不會(huì)crash悲酷,是因?yàn)閷ふ覍?duì)象時(shí)isa指針就得到0返回值。元對(duì)象內(nèi)部存放著類方法列表亲善,而對(duì)象方法列表存儲(chǔ)在類對(duì)象中设易。
那么類方法和實(shí)例方法有何不同?類方法是屬于類對(duì)象的蛹头,所以只能給類對(duì)象調(diào)用顿肺,self也是指類對(duì)象戏溺,不能調(diào)用對(duì)象方法。實(shí)例方法是屬于實(shí)例對(duì)象屠尊,只能通過實(shí)例對(duì)象調(diào)用旷祸,self就是指實(shí)例對(duì)象,也可以調(diào)用類方法讼昆。
通過短暫了解對(duì)象的各種姿勢(shì)托享,我們來(lái)舉個(gè)栗子。
self = [super init];
這在重寫對(duì)象初始化時(shí)都會(huì)調(diào)用浸赫,但我們這時(shí)候調(diào)用[self class]和[super class]得出的結(jié)果會(huì)一樣嘛闰围?答案是一樣的。原因是根據(jù)super是一個(gè)magic keyword掺炭,它是個(gè)編譯器標(biāo)示符和self指向的是同一個(gè)對(duì)象接受者辫诅。super的方法調(diào)用的函數(shù)是objc_msgSendSuper(struct objc_super *super, SEL op, ...)
struct objc_super {
__unsafe_unretained?id?receiver;
__unsafe_unretained?Class?super_class;
};
第一個(gè)receiver類似objc_msgSend的receiver,第二個(gè)參數(shù)是當(dāng)前類的父類涧狮。在[self class]中objc_msgSend中self查找炕矮,沒有,最后通過父類查找在nsobject中找到得到當(dāng)前類者冤。而[super class]首先構(gòu)造結(jié)構(gòu)體objc_super肤视,第一個(gè)為self,所以查找到父類,然后在父類的方法列表中查找class涉枫,最后還是在nsobject的class中找到方法邢滑,而處理的對(duì)象還是self,所以兩者的結(jié)果相同~有點(diǎn)繞
如果有錯(cuò)漏愿汰,請(qǐng)一定告訴我困后,學(xué)習(xí)還在繼續(xù)!THX