一腹缩、說明
super:只是一個(gè)編譯器指示符屿聋,并不是指針或者對(duì)象,它只是標(biāo)識(shí)當(dāng)前對(duì)象去調(diào)用父類的方法
self: 實(shí)例方法里的self藏鹊,是對(duì)象的首地址 润讥,類方法里的 self 是 Class.
二、相關(guān)用法和區(qū)別
- [super class]
- [self class]
- [self superclass]
- [super superclass]
- self = [super init]
首先我們創(chuàng)建兩個(gè)類ClassA 盘寡、 ClassB ,讓ClassB繼承ClassA
@interface ClassA : NSObject
- (void)classAMethod;
@end
#import "ClassA.h"
@implementation ClassA
- (void)classAMethod{
NSLog(@"調(diào)用了ClassA中的方法");
}
@end
#import "ClassA.h"
@interface ClassB :ClassA
- (void)classBMethod;
- (void)test;
@end
#import "ClassB.h"
@implementation ClassB
- (instancetype)init {
self = [super init];
if (self){
}
return self;
}
- (void)classBMethod {
NSLog(@"[super class] == %@",[super class]);
NSLog(@"[self class] == %@",[self class]);
NSLog(@"[self superclass] == %@",[self superclass]);
NSLog(@"[super superclass] == %@",[super superclass]);
}
- (void)classAMethod {
NSLog(@"調(diào)用了ClassB中的方法");
}
- (void)test{
[self classAMethod];
[super classAMethod];
}
@end
我們?cè)? ViewController 中初始化 ClassB的實(shí)例 并調(diào)用 classBMethod 方法楚殿,得到下面的結(jié)果
- (void)viewDidLoad {
[super viewDidLoad];
ClassB *instanceB = [[ClassB alloc] init];
[instanceB classBMethod];
}
2018-07-04 14:23:20.072983+0800 OCCodeDemo[73161:3730280] [super class] == ClassB
2018-07-04 14:23:20.073119+0800 OCCodeDemo[73161:3730280] [self class] == ClassB
2018-07-04 14:23:20.073237+0800 OCCodeDemo[73161:3730280] [self superclass] == ClassA
2018-07-04 14:23:20.073358+0800 OCCodeDemo[73161:3730280] [super superclass] == ClassA
我們可以看到 [super class] 和 [self class] 得到的結(jié)果是一樣的,都指向了當(dāng)前類ClassB竿痰,[self superclass] 和 [super superclass]都指向了父類ClassA脆粥,我們把 ClassB.m 文件編譯成 運(yùn)行時(shí)的代碼看一下,下面是classBMethod 方法運(yùn)行時(shí)代碼
static void _I_ClassB_classBMethod(ClassB * self, SEL _cmd) {
NSLog((NSString *)&__NSConstantStringImpl__var_folders_ps_vpyt2wb51qqcqlxlfqlntnmw0000gn_T_ClassB_942b53_mi_0,((Class (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("ClassB"))}, sel_registerName("class")));
NSLog((NSString *)&__NSConstantStringImpl__var_folders_ps_vpyt2wb51qqcqlxlfqlntnmw0000gn_T_ClassB_942b53_mi_1,((Class (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("class")));
NSLog((NSString *)&__NSConstantStringImpl__var_folders_ps_vpyt2wb51qqcqlxlfqlntnmw0000gn_T_ClassB_942b53_mi_2,((Class (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("superclass")));
NSLog((NSString *)&__NSConstantStringImpl__var_folders_ps_vpyt2wb51qqcqlxlfqlntnmw0000gn_T_ClassB_942b53_mi_3,((Class (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("ClassB"))}, sel_registerName("superclass")));
}
可以看到消息的接收者都是 self 影涉,也就是對(duì)象 instanceB (class 與 superclass 都是 NSObject 類中的內(nèi)部函數(shù))
這里的 sel_registerName 官方給出的定義是:Registers a method with the Objective-C runtime system, maps the method name to a selector, and returns the selector value
也就是說把方法注冊(cè)到運(yùn)行時(shí)系統(tǒng)中变隔,并把方法名字和selector 做映射,并返回 selector 的 值
接下來我們調(diào)用 test 方法蟹倾,得到了下面的結(jié)果
2018-07-04 15:07:49.387521+0800 OCCodeDemo[74261:3766110] 調(diào)用了ClassB中的方法
2018-07-04 15:07:49.387635+0800 OCCodeDemo[74261:3766110] 調(diào)用了ClassA中的方法
如果我們 把 classB中的 classAMethod 方法去掉匣缘,在次調(diào)用test 方法 ,會(huì)得到如下結(jié)果
2018-07-04 15:21:52.620538+0800 OCCodeDemo[74537:3777302] 調(diào)用了ClassA中的方法
2018-07-04 15:21:52.620654+0800 OCCodeDemo[74537:3777302] 調(diào)用了ClassA中的方法
出現(xiàn)這樣的結(jié)果主要原因和ObjectIve-C中runtime消息機(jī)制有關(guān)鲜棠,[self classAMethod]會(huì)被編譯器轉(zhuǎn)化為objc_msgSend(self,@selector(classAMethod)) , [super classAMethod]會(huì)被編譯器轉(zhuǎn)化為 objc_msgSendSuper(self, classAMethod) , self 是先查找本類的IMP肌厨,找到對(duì)應(yīng)的函數(shù)就進(jìn)行執(zhí)行,如果沒有找到就會(huì)到父類/超類中去查找 豁陆,而 super 是先從父類進(jìn)行查找柑爸,找到對(duì)應(yīng)的函數(shù)進(jìn)行執(zhí)行,如果沒有找到則繼續(xù)向父/超類查找盒音,但是接受消息的對(duì)象都是self 表鳍,至于為什么是self何址,我們看一下運(yùn)行時(shí) 代碼 ,可以看到接收消息的對(duì)象都是 self
static void _I_ClassB_test(ClassB * self, SEL _cmd) {
((void (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("classAMethod"));
((void (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("ClassB"))}, sel_registerName("classAMethod"));
}
以上的例子进胯,很好的說明了Super作為編譯標(biāo)識(shí)符,標(biāo)識(shí)當(dāng)前對(duì)象去調(diào)用父類的方法原押,但是接受消息的還是當(dāng)前對(duì)象
接下來我們探討下 self = [super init]
對(duì)于[super init]大家都非常熟悉了胁镐,但是[super init] 之后為什么會(huì)把值賦給self ,我們看下 NSObject.m 中的 init 方法實(shí)現(xiàn)
- (id)init {
return _objc_rootInit(self);
}
id
_objc_rootInit(id obj)
{
// In practice, it will be hard to rely on this function.
// Many classes do not properly chain -init calls.
return obj;
}
轉(zhuǎn)化成 運(yùn)行時(shí)代碼如下:
static instancetype _I_ClassB_init(ClassB * self, SEL _cmd) {
self = ((ClassB *(*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("ClassB"))}, sel_registerName("init"));
if (self){
}
return self;
}
從運(yùn)行時(shí)的代碼可以看出诸衔,[super init] 最終返回的是一個(gè) ClassB 的實(shí)例對(duì)象盯漂,并賦值給 self
三、總結(jié)
本篇文章只是介紹了關(guān)鍵字符 super的定義和作用以及在系統(tǒng)運(yùn)行時(shí)和self的關(guān)系笨农,并未對(duì)self的做更詳細(xì)的探討就缆,如有不足之處歡迎指正,共同學(xué)習(xí)進(jìn)步