这一个经典的面试题, Student 是 Person 的一个子类, 在子类 Student 的 init 方法中调用 4 个方法并打印结果.
objc_msgSend(self, sel_registerName("class")) objc_msgSend(self, sel_registerName("superclass")) objc_msgSendSuper({self, class_getSuperclass(objc_getClass("Student"))}, sel_registerName("class")) objc_msgSendSuper({(id)self, (id)class_getSuperclass(objc_getClass("Student"))}, sel_registerName("superclass"))
将这个 Student.m 转换为 cpp 文件查看其底层的方法调用的到如下调用:
- [self class]: objc_msgSend(self, sel_registerName("class"))
- [self superclass]: objc_msgSend(self, sel_registerName("superclass"))
- [super class]: objc_msgSendSuper({
- self, class_getSuperclass(objc_getClass("Student"))
- }, sel_registerName("class"))
- [super superclass]: objc_msgSendSuper({
- self, class_getSuperclass(objc_getClass("Student"))
- }, sel_registerName("superclass"))
我们看到当对 self 进行消息发送的时候底层是调用了 runtime 的 objc_msgSend 方法, 而对 super 进行消息发送的时候底层是调用了 objc_getSuperClass.
objc_msgSend 方法我们都熟悉了, 将会从 self 开始查找 class 方法和 superclass 方法的实现, 调用打印 Student 和 Person.
而对 super 发送消息, 底层将会调用 objc_msgSendSuper 函数, 这个函数有两个参数, 第一个是一个结构, 第二个是方法选择器. 结构体有两个成员:
第一个是消息接受者, 第二个参数我们通过注释可以看出, 表示函数从哪里开始查找法方法. 而这里传递的是 class_getSuperclass(objc_getClass("Student"))表示 Student 的父类, 也就是 Person 类开始查找方法. 查找的方法是 class 和 superclass, 而这两个方法存在于 NSObject 中, 查找到了之后依然使用 objc_msgSendSuper 第一个参数结构体的第一个成员接收消息. 消息接受者是 self, 所以依然调用 self 的 class 方法和 superclass.
所以最终 [super class] 和[super superclass]打印的依然是 Student 和 Person.
总结
对 super 发消息底层调用的是 objc_msgSendSuper 方法, 它有两个参数, 第一个是一个结构, 第二个是方法选择器. 本质上所做的操作是从当前类的父类开始查找方法, 而消息的接受者依然是 self, 也就是当前类, 所以最后还是[self xxxx].
来源: https://juejin.im/post/5c57d18fe51d45013b076ef5