iOS底层-self、super、superclass
基本理解:
- self : 当前方法的调用者
- super:不是一个指针,编译指示器(标识符),在程序编译时内部会做一些特殊处理 (底层会被编译成 objc_msgSendSuper()方法)
- superclass:是一个方法,返回的结果是调用者的父类对象
super 的作用只是告诉编译器,查找方法的时候不用找自己的方法列表,直接从父类开始找。(调用者还是我自己)
我们在研究方法查找流程的时候知道,发送消息是先找自己的方法,然后递归找父类的方法, 而super就是告诉编译器,不要从我这找了,直接从父类开始找吧。
每当讲解self与super的时候,都会拿这个经典的代码示例来做说明:
// 背景 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]) 打印结果
self = Student
super = Student
/**
⚠️ 如果 定义一个Student子类 : StudentChild : Student
子类 StudentChild 不重写 init方法
执行 [StudentChild new];
那么这里打印的 是
self = StudentChild
super = StudentChild
*/
⚠️:self 和 super 都是调用者
Sutdent 调用init 那么 self、super 就是Student
StudentChild 调用init 那么 self、super 就是StudentChild
按照一般人的想法:这里的super 应该是Person,而实际上却是Student,那是因为 在理解super之前
容易将super 和 superclass混淆
从源码来分析self、super
上面有说到:super 是 编译指示器(标识符)
而不是指针,self是方法调用者,是一个指针
⚠️ 只要记住super 不是 superclass,理解super就很容易了
我们从汇编代码来看看,他究竟干了什么
cd 到Student.m的上一级目录,然后通过命令:
clang -rewrite-objc Student.m
// 或者
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc Student.m -o out.cpp (Student.m 是需要转换的文件 out.cpp 是转换之后的名字,也可以省略,默认原来的名字(从-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;
}
//简化之后
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;
}
从简化之后的代码能看以下信息
- 1、调用[self class]的时候,底层是调用的 objc_msgSend(....)
- 2、调用[super class]的时候,底层调用的是 objc_msgSuperSend(....)
- 3、super调用的方法,从父类开始查找[class_getSuperclass(...)]
知道了调用的方法之后,我们从底层源码源码页面中搜索objc
来分析:
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相对比较好理解,对应到这里,[self class] 就是 objc_msgSend(调用者(self),调用方法(@selecter(class)),....(其他参数))
[super class] 中 objc_msgSendSuper() 的参数是一个objc_super结构体 结构体的第一个参数和objc_msgSend一样,也是receive(self),只是通过第二个参数 super_class 知道,方法从父类去找
可以理解为 objc_msgSendSuper(调用者(self),从哪开始找(super_class),调用方法(@selecter(class)),....(其他参数))
self 再探
上面说了super的理解,接下来对self梳理一遍
// 背景 Person:NSObject Student:Person
//Person 声明并实现 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 并调用readBook
Student *s = [Student new];
[s readBook];
//先思考答应结果,再看运行结果
//打印结果
person readBook self = Student
Student readbook
上面的代码中,在Person中的[self class] 中的self 依然是Student,因为最开始就说过,self是调用者,在这里 是student调用了 readBook,所以,即使[self class]在Person,依然是Student
superclass
- superclass:是一个方法,返回的结果是调用者的父类对象(有类方法和示例方法)
从源码中看
+ (Class)superclass {
return self->superclass;
}
- (Class)superclass {
return [self class]->superclass;
}
掉用superclass就是获取对象所在类的superclass 从对象本质(结构体)中看:
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);
}
.......
}