一、准备代码
Person继承自NSObject, 并实现-run方法

Student继承自Person, 并重写-run方法

- 在
main函数中, 执行下面的代码, 可以看到Person和Student方法中的run都有打印结果

- 那么
super在底层是什么样的呢?
二、super
- 使用终端, 执行下面的命令, 生成
Student.cpp文件
xcrun -sdk iphoneos clang -arch arm64 -rewrite-objc Student.m
- 可以在
Student.cpp文件中找到-run方法的底层代码

- 下面一句, 就是
[super run];代码部分
((void (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Student"))}, sel_registerName("run"));
- 去掉类型转换
objc_msgSendSuper((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Student"))},
sel_registerName("run"));
- 将第一个参数抽出
__rw_objc_super arg = {
self,
class_getSuperclass(objc_getClass("Student"))
};
objc_msgSendSuper(arg, sel_registerName("run"));
-
可以看到
super的底层调用了objc_msgSendSuper方法, 并传入两个参数- __rw_objc_super: 结构体
- sel_registerName("run"): 方法SEL
-
查看源码中
objc_super结构体

- 去掉没有用的代码, 整理如下
struct objc_super {
__unsafe_unretained _Nonnull id receiver;
__unsafe_unretained _Nonnull Class super_class;
};
-
可以看到, 第一个成员变量是
receiver, 第二个成员变量是super_class -
继续查看
objc_msgSendSuper函数的定义

-
在注释中可以看到对
objc_super两个成员变量的解释receiver: 消息接收者super_class: 从super_class开始查找调用的方法
-
从实际代码中可以看到, 这两个成员变量分别传入了
self和[Person class]
__rw_objc_super arg = {
self, // receiver
class_getSuperclass(objc_getClass("Student")) // super_class
};
- 所以消息接收者是
self, 从[Person class]中开始查找方法 objc_msgSendSuper的第二个参数是sel_registerName("run"), 即@selector(run)- 所以
[super run];在底层代码的原意是: 给self发送一条消息, 消息名称是run, 这条消息从[Person class]开始查找
总结:
super的含义是, 查询方法的起点是父类, 不是本身的类对象
消息接收者是self, 不是父类对象
发送的消息是调用的方法
三、面试题
- 下面的代码, 运行结果是什么, 为什么

- 运行程序, 打印如下

2019-03-13 21:00:24.318811+0800 super[6493:1374771] Student
2019-03-13 21:00:24.319059+0800 super[6493:1374771] Person
2019-03-13 21:00:24.319077+0800 super[6493:1374771] ---------------------
2019-03-13 21:00:24.319093+0800 super[6493:1374771] Student
2019-03-13 21:00:24.319111+0800 super[6493:1374771] Person
打印分析
- 查看底层源码

- 去掉类型转换, 底层代码如下
objc_msgSend(self, sel_registerName("class")
objc_msgSend(self, sel_registerName("superclass"))
objc_msgSendSuper((__rw_objc_super){self, class_getSuperclass(objc_getClass("Student"))}, sel_registerName("class"))
objc_msgSendSuper((__rw_objc_super){self, class_getSuperclass(objc_getClass("Student"))}, sel_registerName("superclass"))
- 前两个方法是给
self发送消息, 消息名称是class和superclass, 结果很明显就是查看自己的类型和父类的类型 - 后两个方法也是给
self发送消息, 只不过是从父类开始查询class和superclass方法, 而这两个方法都存在于NSObject中 - 消息接收者同样是
self, 调用的方法也是相同, 所以结果就是自己的类型和父类的类型