如果您希望拥有更好的阅读体验,欢迎访问 我的开发笔记
一道面试题引发的,对于super本质的探究
@implementation RTStudent
-(instancetype)init {
if (self = [super init]) {
NSLog(@"self和super调用class的结果:");
NSLog(@"[self class]---%@",[self class]);
NSLog(@"[super class]---%@",[super class]);
NSLog(@"self和super调用superclass的结果:");
NSLog(@"[self superclass]---%@",[self superclass]);
NSLog(@"[super superclass]---%@",[super superclass]);
}
return self;
}
@end
下边的代码打印的是什么?
int main(int argc, const char * argv[]) {
@autoreleasepool {
__unused RTStudent *stu = [[RTStudent alloc] init];
}
return 0;
}
结果如下
self和super调用class的结果:
[self class]---RTStudent
[super class]---RTStudent
self和super调用superclass的结果:
[self superclass]---RTPerson
[super superclass]---RTPerson
为什么是这样的结果呢?super
到底是怎么来发消息的?做一个测试:
@implementation RTStudent
-(void)run{
[super run];
NSLog(@"RTStudent--run");
}
@end
运行命令xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc RTStudent.m
将RTStudent.m
转为c++
文件,去掉打印和类型强转后为:
static void _I_RTStudent_run(RTStudent * self, SEL _cmd) {
objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("RTStudent"))}, sel_registerName("run"));
}
第一个参数是个结构体,再次抽取后:
static void _I_RTStudent_run(RTStudent * self, SEL _cmd) {
__rw_objc_super arg = {
(id)self,
(id)class_getSuperclass(objc_getClass("RTStudent"))
}
objc_msgSendSuper(arg, sel_registerName("run"));
}
将runtime函数转为oc:
class_getSuperclass(objc_getClass("RTStudent")) ==> [RTPerson class]
sel_registerName("run") ==> @selector(run)
最终为:
static void _I_RTStudent_run(RTStudent * self, SEL _cmd) {
__rw_objc_super arg = {self, [RTPerson class]}
objc_msgSendSuper(arg, @selector(run));
}
在runtime源码中找到objc_super
结构体定义:
/// Specifies the superclass of an instance.
struct objc_super {
id receiver; //消息接受者
Class super_class; //消息接受者父类
};
objc_msgSendSuper
方法定义为:
objc_msgSendSuper(struct objc_super * super, SEL op, ...)
有文档including the instance of the class that is to receive the message and the superclass at which to start searching for the method implementation
可知方法的接收者为结构体中的receiver
,查找方法的时候从结构体中的super_class
开始,而clas的方法实现为
- (Class)class {
return object_getClass(self);
}
所以object_getClass(self)
中的self
就是objc_super
这个结构体中的receiver
,所以[self class]
会和[super class]
的一样
以上只是转为c++代码的分析,实际通过打断点查看汇编代码发现,调用的函数是objc_msgSendSuper2
(源码在objc-msg-arm64.s文件中,查看函数实现)
0x100000c0c <+28>: movq 0x6d5(%rip), %rsi ; (void *)0x0000000100001340: RTStudent
0x100000c13 <+35>: movq %rsi, -0x18(%rbp)
0x100000c17 <+39>: movq 0x69a(%rip), %rsi ; "run"
0x100000c1e <+46>: movq %rax, %rdi
0x100000c21 <+49>: callq 0x100000e54 ; symbol stub for: objc_msgSendSuper2
0x100000c26 <+54>: leaq 0x41b(%rip), %rax ; @"RTStudent--run"
而且传入的结构体是objc_super2
struct objc_super2 {
id receiver;
Class current_class;
};
可以看到第二个变量变为current_class
了,那么查找方法时会在当前类对象里查找吗?
ldr p16, [x16, #SUPERCLASS] // p16 = class->superclass
在objc_msgSendSuper2
源码中,发现这句注释class->superclass
,所以最终它还是会直接从父类对象中查找方法