基本理解:
- self : 當(dāng)前方法的調(diào)用者
- super:不是一個(gè)指針,編譯指示器(標(biāo)識(shí)符),在程序編譯時(shí)內(nèi)部會(huì)做一些特殊處理 (底層會(huì)被編譯成 objc_msgSendSuper()方法)
- superclass:是一個(gè)方法畔濒,返回的結(jié)果是調(diào)用者的父類對(duì)象
super 的作用只是告訴編譯器剩晴,查找方法的時(shí)候不用找自己的方法列表,直接從父類開始找侵状。(調(diào)用者還是我自己)
我們?cè)谘芯糠椒ú檎伊鞒痰臅r(shí)候知道赞弥,發(fā)送消息是先找自己的方法,然后遞歸找父類的方法趣兄, 而super就是告訴編譯器绽左,不要從我這找了,直接從父類開始找吧艇潭。
每當(dāng)講解self與super的時(shí)候拼窥,都會(huì)拿這個(gè)經(jīng)典的代碼示例來(lái)做說(shuō)明:
// 背景 Person:NSObject Student:Person
//重寫Student的init方法
- (instancetype)init
{
if (self = [super init]) {
NSLog(@"self = %@",NSStringFromClass([self class]));
NSLog(@"super = %@",NSStringFromClass([super class]));
}
return self;
}
//初始化Studen([Student new]) 打印結(jié)果
self = Student
super = Student
/**
?? 如果 定義一個(gè)Student子類 : StudentChild : Student
子類 StudentChild 不重寫 init方法
執(zhí)行 [StudentChild new];
那么這里打印的 是
self = StudentChild
super = StudentChild
*/
??:self 和 super 都是調(diào)用者
Sutdent 調(diào)用init 那么 self、super 就是Student
StudentChild 調(diào)用init 那么 self蹋凝、super 就是StudentChild
按照一般人的想法:這里的super 應(yīng)該是Person鲁纠,而實(shí)際上卻是Student,那是因?yàn)?在理解super之前
容易將super 和 superclass混淆
從源碼來(lái)分析self鳍寂、super
上面有說(shuō)到:super 是 編譯指示器(標(biāo)識(shí)符)
而不是指針改含,self是方法調(diào)用者,是一個(gè)指針
?? 只要記住super 不是 superclass迄汛,理解super就很容易了
我們從匯編代碼來(lái)看看候味,他究竟干了什么
cd 到Student.m的上一級(jí)目錄,然后通過命令:
clang -rewrite-objc Student.m
// 或者
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc Student.m -o out.cpp (Student.m 是需要轉(zhuǎn)換的文件 out.cpp 是轉(zhuǎn)換之后的名字隔心,也可以省略,默認(rèn)原來(lái)的名字(從-o 開始省略))
可以找到這樣一段底層代碼
static instancetype _I_Student_init(Student * self, SEL _cmd) {
if (self = ((Student *(*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Student"))}, sel_registerName("init"))) {
NSLog((NSString *)&__NSConstantStringImpl__var_folders_p8_l89z5sss5qx7r1082_jrxy_40000gp_T_Student_3430f4_mi_0,NSStringFromClass(((Class (*)(id, SEL))(void *)objc_msgSend)((id)self, sel_registerName("class"))));
NSLog((NSString *)&__NSConstantStringImpl__var_folders_p8_l89z5sss5qx7r1082_jrxy_40000gp_T_Student_3430f4_mi_1,NSStringFromClass(((Class (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Student"))}, sel_registerName("class"))));
}
return self;
}
//簡(jiǎn)化之后
static instancetype _I_Student_init(Student * self, SEL _cmd) {
if (self = ((Student *(*)objc_msgSendSuper)({(id)self, (id)class_getSuperclass(objc_getClass("Student"))}, sel_registerName("init"))) {
NSLog(NSStringFromClass(objc_msgSend)((id)self, sel_registerName("class"))));
NSLog(NSStringFromClass(objc_msgSendSuper)({(id)self, (id)class_getSuperclass(objc_getClass("Student"))}, sel_registerName("class"))));
}
return self;
}
從簡(jiǎn)化之后的代碼能看以下信息
- 1尚胞、調(diào)用[self class]的時(shí)候硬霍,底層是調(diào)用的 objc_msgSend(....)
- 2、調(diào)用[super class]的時(shí)候笼裳,底層調(diào)用的是 objc_msgSuperSend(....)
- 3唯卖、super調(diào)用的方法粱玲,從父類開始查找[class_getSuperclass(...)]
知道了調(diào)用的方法之后,我們從底層源碼源碼頁(yè)面中搜索objc
來(lái)分析:
OBJC_EXPORT void
objc_msgSend(void /* id self, SEL op, ... */ )
OBJC_EXPORT void
objc_msgSendSuper(void /* struct objc_super *super, SEL op, ... */ )
struct objc_super {
/// Specifies an instance of a class.
__unsafe_unretained _Nonnull id receiver;
__unsafe_unretained _Nonnull Class super_class;
};
objc_msgSend相對(duì)比較好理解拜轨,對(duì)應(yīng)到這里抽减,[self class] 就是 objc_msgSend(調(diào)用者(self),調(diào)用方法(@selecter(class))橄碾,....(其他參數(shù)))
[super class] 中 objc_msgSendSuper() 的參數(shù)是一個(gè)objc_super結(jié)構(gòu)體 結(jié)構(gòu)體的第一個(gè)參數(shù)和objc_msgSend一樣卵沉,也是receive(self),只是通過第二個(gè)參數(shù) super_class 知道法牲,方法從父類去找
可以理解為 objc_msgSendSuper(調(diào)用者(self)史汗,從哪開始找(super_class),調(diào)用方法(@selecter(class)),....(其他參數(shù)))
self 再探
上面說(shuō)了super的理解拒垃,接下來(lái)對(duì)self梳理一遍
// 背景 Person:NSObject Student:Person
//Person 聲明并實(shí)現(xiàn) readBook方法
//Person.h
- (void)readBook;
//Person.m
- (void)readBook
{
NSLog(@"person readBook self = %@",NSStringFromClass([self class]));
}
//Student 重寫readBook
- (void)readBook
{
[super readBook];
NSLog(@"Student readbook");
}
//初始化Studen 并調(diào)用readBook
Student *s = [Student new];
[s readBook];
//先思考答應(yīng)結(jié)果停撞,再看運(yùn)行結(jié)果
//打印結(jié)果
person readBook self = Student
Student readbook
上面的代碼中,在Person中的[self class] 中的self 依然是Student悼瓮,因?yàn)樽铋_始就說(shuō)過戈毒,self是調(diào)用者,在這里 是student調(diào)用了 readBook横堡,所以埋市,即使[self class]在Person,依然是Student
superclass
- superclass:是一個(gè)方法翅萤,返回的結(jié)果是調(diào)用者的父類對(duì)象(有類方法和示例方法)
從源碼中看
+ (Class)superclass {
return self->superclass;
}
- (Class)superclass {
return [self class]->superclass;
}
掉用superclass就是獲取對(duì)象所在類的superclass 從對(duì)象本質(zhì)(結(jié)構(gòu)體)中看:
struct objc_class : objc_object {
// Class ISA;
Class superclass; // <-----?? 就是它
cache_t cache;
class_data_bits_t bits;
class_rw_t *data() {
return bits.data();
}
void setData(class_rw_t *newData) {
bits.setData(newData);
}
.......
}