学习MJ的视频课程,整理总结知识点–super、class面试题
本文讲解super、class相关的一些面试题,利用底层的知识来分析讲解
面试题01-super
先看一段代码,同时附上了分析时的DemoInterview05-super
1 | @interface MJPerson : NSObject |
问:打印结果是什么?
验证后的输出结果如下
1 | NSLog(@"[self class] = %@", [self class]); // MJStudent |
对于[self class]
、[self superclass]
的结果我们基本上没什么疑问,对于[super class]
的结果,可能会觉得意外。
下面结合Demo以及编译后的源码分析为什么是这样。
先从简答的super
调用分析,代码如下
1 | @implementation MJStudent |
利用clang编译对应部分的源码,结果如下
1 | ((void (*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("MJStudent"))}, sel_registerName("run")); |
我们发现,objc_msgSendSuper
的参数有两个,一个是结构体,一个是SEL,我们搜索源码发现这个结构体相关的代码
1 | /// Specifies the superclass of an instance. |
objc_super
的结构和__rw_objc_super
是一致的,其实它们两个也是等价的,只不过是程序在不同阶段的表现不同而已。
所以,可以整理出super方法调用对应的源码
1 | struct objc_super { |
objc_super
中的receiver
消息接受者是self
,即[super run]
中super调用的receiver仍然是MJStudent
对象。
下面的关键就是看objc_msgSendSuper
的实现,但是这部分是汇编代码,不过能看到它的注释,写的也很清晰,如下
1 | /** |
这段注释也说明[super message]
的底层实现原理
- 消息接收者仍然是子类对象
- 从父类开始查找方法的实现
分析完后,继续回到[super class]
这段代码
1 | NSLog(@"[super class] = %@", [super class]); |
结合上面的super分析,我们可知[super class]
这个方法的接受者仍然是当前的子类对象(MJStudent
)。
对于-class
方法,结合我们在object_getClass
所学的知识,它的实现如下
1 | - (Class)class { |
所以[super class]
的消息接收者是当前的子类对象,而-class
方法就是返回方法调用者的class,也就是MJStudent
类型
总结
[super message]
转化的底层源码
struct objc_super {
__unsafe_unretained _Nonnull id receiver; // 消息接收者
__unsafe_unretained _Nonnull Class super_class; // 消息接收者的父类
};
struct objc_super arg = {self, 父类};
objc_msgSendSuper(arg, SEL);
[super message]
的底层实现
消息接收者仍然是子类对象
从父类开始查找方法的实现[super message], [self message]
这两个函数的实现差别挺大,一个调用objc_msgSendSuper
,一个调用objc_msgSend
,不要被它们两个表面迷惑;-class
的底层实现
返回的是消息接收者的类,而恰好super
的消息接收者是子类对象,就解释了[super class]
的结果是子类了。