开始
创建一个 Test 测试类, 重写初始化方法:
1 | - (instancetype)init { |
疑问:
- 为何要执行
[super init]? [super init]的结果为何要self接收?
探索:
[super init]
这一句看起来很有迷惑性, 一个 super 关键字, 好像初始化的是父类, 但在码代码的时候可以注意一个细节: 在写 self 时, 代码提示是有返回值类型的, 而写 [super init] 时, 并没有返回值类型, 但在别处写 super 时, 自动提示的返回值类型是父类.
这表示在 [super init] 这句话中, super 并不是指父类, 可能只是一个没有什么卵用的关键字, 但在苹果的官方文档中, 这么写是推荐的写法, 那么这句话就很关键了.
通过 clang -rewrite-objc Test.m 命令, 重新编译成 cpp 文件, 可以看到这一行代码究竟做了什么:
1 | static instancetype _I_Test_init(Test * self, SEL _cmd) { |
经过简化后, [super init] 就变为
1 | objc_msgSendSuper({self, class_getSuperclass(objc_getClass("Test"))}, sel_registerName("init")); |
而其中 objc_msgSendSuper() 这个方法, API 文档是这样描述的:
1 OBJC_EXPORT void objc_msgSendSuper(void /* struct objc_super *super, SEL op, ... */ ) OBJC_AVAILABLE(10.0, 2.0, 9.0, 1.0);Sends a message with a simple return value to the superclass of an instance of a class.
将具有返回值的消息发送到一个实例的超类.
第一个参数是 objc_suoer 类型的结构体, 第二个或更多是 SEL 方法选择器, 而在 runtime.m 文档中, objc_super 的结构为:
1 | struct objc_super { |
receiver 是实例对象, super_class 是用来接收消息的类, 为实例对象的父类.
在当前的代码里, receiver 为 self , super_class 为 NSObject .
再回过头来, 注意看 [super init] 的 c++ 源码, 返回值为 Test *, 所以在这里的 init 只是向上初始化父类而已.
那么这就明了了, [super init] 只是为了将父类, 父类的父类, 父类的父类的父类等等等等, 从 NSObject 开始的所有类都初始化了一遍, 只是为了确保父类的方法, 属性都能正确使用而已.
self = [super init]
既然明白了 [super init] 做了什么, 那么返回结果再赋值给 self 就基本没有疑问了: 如果在 [super init] 这一步因为一些不明的原因导致初始化失败, 那么返回值应该是为 nil 的, 这时候让 self 接收一下, 之后用 if 判断, 则可以避免一些 BUG.
总结
- 为何要执行
[super init]?- 为了将当前实例的父类树进行初始化, 以保证继承父类树的所有属性与方法.
[super init]的结果为何要self接收?- 为了确保初始化不会因为失败而 crash.