本文的切入点是 2014 年的一场线下分享会, 也就是 sunnyxx 分享的 objc runtime. 很惭愧, 这么多年了才完整的看了一下这个分享会视频. 当时他出了一份试题, 并戏称精神病院 objc runtime 入院考试.
我们今天的这篇文章就是从这个试题中的题目入手, 来深入的学习 runtime.
源码版本 objc4-750
第一题
- @implementation Son : Father
- - (id)init {
- self = [super init];
- if (self) {
- NSLog(@"%@", NSStringFromClass([self class]));
- NSLog(@"%@", NSStringFromClass([super class]));
- }
- return self;
- }
- @end
第一行的 [self class] 应该是没有疑问的, 肯定是 Son, 问题就出在这个[super class].
大家都知道, 我们 OC 的方法在底层会编译为一个 objc_msgSend 的方法 (消息发送),[self class] 符合这个情况, 因为 self 是类的一个隐藏参数. 但是 super 并不是一个参数, 它是一个关键字, 实际上是一个 "编译器标示符", 所以这就有点不一样了, 经查阅资料, 在调用 [super class] 的时候, runtime 调用的是 objc_msgSendSuper 方法, 而不是 objc_msgSend.
首先要做的是验证一下是否是调用了 objc_msgSendSuper. 这里用到了 clang 这个工具, 我们可以把 OC 的代码转成 C/C++.
- @implementation Son
- - (void)test {
- [super class];
- }
- @end
在终端运行 clang -rewrite-objc Son.m 生成一个 Son.cpp 文件.
在这个. cpp 文件的底部我们可以找到这么一部分代码
- // @implementation Son
- static void _I_Son_test(Son * self, SEL _cmd) {
- ((Class (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Son"))}, sel_registerName("class"));
- }
- // @end
看起来乱七八糟, 有很多强制类型转换的代码, 不用理它, 我们只要看到了我们想要的 objc_msgSendSuper 就好.
去源码中看一下这个方法(具体实现好像是汇编, 看不懂)
- OBJC_EXPORT void
- objc_msgSendSuper(void /* struct objc_super *super, SEL op, ... */ )
- OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0, 2.0);
可以看出来这个方法第一个参数是一个 objc_super 类型的结构体, 第二个是一个我们常见的 SEL, 后面的... 代表还有扩展参数.
再看一下这个 objc_super 结构体.
- /// Specifies the superclass of an instance.
- struct objc_super {
- /// Specifies an instance of a class.
- __unsafe_unretained _Nonnull id receiver;
- /// Specifies the particular superclass of the instance to message.
- #if !defined(__cplusplus) && !__OBJC2__
- /* For compatibility with old objc-runtime.h header 为了兼容老的 */
- __unsafe_unretained _Nonnull Class class;
- #else
- __unsafe_unretained _Nonnull Class super_class;
- #endif
- /* super_class is the first class to search */
- };
第一个参数是接收消息的 receiver, 第二个是 super_class(见名知意~ ). 我们和上面提到的. cpp 中的代码对应一下就会发现重点了, receiver 是 self.
所以, 这个 [super class] 的工作原理是, 从 objc_super 结构体的 super_class 指向类的方法列表开始查找 class 方法, 找到这个方法之后使用 receiver 来调用.
所以, 调用 class 方法的其实还是 self, 结果也就是打印 Son.
来源: http://www.jianshu.com/p/25ca8ccfb998