1、问题思考
创建Person类和Person的子类Student,在Student内部添加如下代码,观察两组打印结果:
NSLog(@"第一组----------");
NSLog(@"[self class] %@", [self class]);
NSLog(@"[self superclass] %@", [self superclass]);
NSLog(@"第二组----------");
NSLog(@"[super class] %@", [super class]);
NSLog(@"[super superclass] %@", [super superclass]);
打印结果:
~: 第一组----------
~: [self class] Student
~: [self superclass] Person
~: 第二组----------
~: [super class] Student
~: [super superclass] Person
如果super代表的是父类,那么为什么self和super调用class的结果相同?
2、super的结构
为Person和Student都添加run方法,在Student执行run方法时调用父类run方法:
- (void)run {
[super run];
}
转成C++代码:
((void (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Student"))}, sel_registerName("run"));
整理一下:
struct objc_super sp = {
self,
[Person class],
};
objc_msgSendSuper(sp, @selector(run));
可以看到使用super关键字调用方法是,底层使用的是objc_msgSendSuper方法,且传入参数为objc_super结构体和SEL,objc_super的结构如下,包含消息接收者和消息接收者的父类两个成员:
struct __rw_objc_super {
struct objc_object *object; // 消息接收者
struct objc_object *superClass; // 消息接收者的父类
};
通过 objc源码 message.h中objc_msgSendSuper方法注释可知,当调用方法时会先在superClass中开始搜索方法实现。
3、class、superclass方法
class方法是在NSObject内部实现的,源码:
- (Class)class {
return object_getClass(self);
}
- (Class)superclass {
return [self class]->getSuperclass();
}
返回的是方法接收者receiver的class(isa指针)。
4、总结
super调用方法底层实际上是通过objc_msgSendSuper方法实现,传入的参数是objc_super结构体,而objc_super结构体的第一个参数是self,所以最后在调用class方法时的receiver还是self,[super message]总结如下:
1、消息接收者仍然是子类对象
2、从父类开始查找方法的实现
所以打印[super class]结果仍然是Student。
5、补充
将super调用转成C++代码后,显示的底层实现是objc_msgSendSuper方法,但真实的底层方法是objc_msgSendSuper2,可以通过汇编代码查看(参考OC代码转换):
0x100003f2e <+46>: callq 0x100003f4c ; symbol stub for: objc_msgSendSuper2
callq _objc_msgSendSuper2
由此可见,super真实底层实现是_objc_msgSendSuper2方法。