前奏
self 是什么翁巍? super 是什么趴腋?
動(dòng)態(tài)方法中:self 是代表 “對(duì)象”,
靜態(tài)方法中:self 是代表 “類(lèi)”鳖链。
self 就代表當(dāng)前方法的調(diào)用者呢袱,
super 相當(dāng)于調(diào)用父類(lèi)的方法官扣。
這個(gè)例子我就不寫(xiě)了。
如果在 init 中調(diào)用 self 和 super 是否會(huì)有不同羞福?
新建一個(gè)類(lèi)叫 Son 繼承 NSObject
- (id)init {
if (self = [super init] ) {
NSLog(@"%@", NSStringFromClass([self class])); // Son
NSLog(@"%@", NSStringFromClass([super class])); // Son
NSLog(@"%@", NSStringFromClass([self superclass])); // Son
}
return self;
}
結(jié)果如下
2017-09-24 13:25:11.109332+0800 Demo[22406:879505] Son
2017-09-24 13:25:11.109567+0800 Demo[22406:879505] Son
2017-09-24 13:25:11.109681+0800 Demo[22406:879505] NSObject
- [self class] 和 [super class] 為什么輸出的類(lèi)型 是一樣的惕蹄?
為什么?
- self 是類(lèi)隱藏的參數(shù)治专,指向當(dāng)前調(diào)用方法的類(lèi)卖陵,另外一個(gè)隱藏參數(shù)是_cmd,代表當(dāng)前類(lèi)方法的 selector张峰。
- super 并不是隱藏參數(shù)泪蔫,只是一個(gè) “編譯器指示符”,它和 self 指向的是相同的消息接收者喘批。所以上面不論是 [self class] 和 [super class] 輸出的類(lèi)型是一樣的撩荣。
- 不同之處: super 會(huì)告訴編譯器,當(dāng)調(diào)用 setXXX 的方法時(shí)谤祖,要去調(diào)用父類(lèi)的方法婿滓,而不是本類(lèi)的。self 會(huì)從當(dāng)前類(lèi)的方法列表中開(kāi)始找粥喜,沒(méi)有的話再去父類(lèi)中找凸主。
又做了一個(gè)實(shí)驗(yàn):
- 又創(chuàng)建了一個(gè)繼承于 Son 的類(lèi) 叫 Bom
- 分別在 Son 和 Bom 實(shí)現(xiàn)了一個(gè) + 號(hào)方法 eat。
- 在 Bom 的 init 方法里面寫(xiě)以下代碼
- (id)init {
if (self = [super init]) {
[[super superclass] eat];
[[self superclass] eat];
[[super class] eat];
[[self class] eat];
}
return self;
}
-
輸出為下面
2017-09-25 09:32:36.390684+0800 Demo[31497:1089563] 執(zhí)行了 Son 的 class 2017-09-25 09:32:36.390756+0800 Demo[31497:1089563] 執(zhí)行了 Son 的 class 2017-09-25 09:32:36.390838+0800 Demo[31497:1089563] 執(zhí)行了 Bom 的 class 2017-09-25 09:32:36.390920+0800 Demo[31497:1089563] 執(zhí)行了 Bom 的 class
結(jié)果和我們得到的結(jié)論是一模一樣的额湘。
原理:
-
這種機(jī)制底層是怎么回事卿吐?
-
Apple 是這樣說(shuō)的
When it encounters a method invocation, the compiler might generate a call to any of several functions to perform the actual message dispatch, depending on the receiver, the return value, and the arguments. You can use these functions to dynamically invoke methods from your own plain C code, or to use argument forms not permitted by NSObject’s perform… methods. These functions are declared in /usr/include/objc/objc-runtime.h.objc_msgSend sends a message with a simple return value to an instance of a class.
objc_msgSend_stret sends a message with a data-structure return value to an instance of a class.
objc_msgSendSuper sends a message with a simple return value to the superclass of an instance of a class.
objc_msgSendSuper_stret sends a message with a data-structure return value to the superclass of an instance of a class.
-
-
這里我們只需要關(guān)注 以下兩個(gè)方法
id objc_msgSend(id theReceiver, SEL theSelector, ...) id objc_msgSendSuper(struct objc_super *super, SEL op, ...)
msgSend 方法
id theReceiver :消息接收者旁舰。
-
SEL theSelector:調(diào)用具體類(lèi)方法的 selector
[self setXXX]; 編譯器會(huì)替換成 objc_msgSend 的函數(shù)調(diào)用。消息的接收者是 self嗡官,所有后面的 selector 會(huì)從當(dāng)前 self 的方法表里面找 setXXX箭窜,找到后把對(duì)應(yīng)的 selector 傳過(guò)去。
msgSendSuper 方法
struct objc_super :是 objc_super 的結(jié)構(gòu)體
-
super, SEL op :類(lèi)似于 selector
struct objc_super 結(jié)構(gòu)體如下
struct objc_super { id receiver; Class superClass; };
- receiver 相當(dāng)于消息接收者
- Class superClass 相當(dāng)于父類(lèi)衍腥,比如在上面的例子 Bom 中調(diào)用 就是他的父類(lèi) Son
大概機(jī)制就這樣了磺樱。
總結(jié):
比如在 Bom 中調(diào)用 [self class]
使用 objc_msgSend 第一個(gè)參數(shù)是 self 也就是 Bom *bom 這個(gè)實(shí)例。
第二個(gè)參數(shù) 找到這個(gè) class 的 selector婆咸。 先去 Bom 這個(gè)類(lèi)去找竹捉,沒(méi)有就去父類(lèi) Son 中找, 也沒(méi)有的話尚骄, 就去 Son 的父類(lèi) NSObject 中找块差,最終在 NSObject 中找到了 這個(gè) class 方法, 然后 返回 receiver 類(lèi)別倔丈, 所以輸出 為 Bom憨闰,-
當(dāng)調(diào)用的是 [super class]
使用 objc_msgSendSuper 的方法
第一個(gè)參數(shù):結(jié)構(gòu)體- 第一個(gè)成員變量: self
- 第二個(gè)成員變量:Son
第二個(gè)參數(shù):去 superClass(Son) 中找 class 方法,沒(méi)有需五,然后去NSObject 中找鹉动,找到了, 然后內(nèi)部使用函數(shù) objc_msgSend(objc_super->receiver, @selector(class)) 去調(diào)用宏邮,這樣就和上面的 [self class] 調(diào)用相同了训裆。所以 此時(shí)的 receiver 還是 Bom *bom,所以返回的也是 Bom蜀铲。