美文网首页iOS开发 Objective-C
深入了解 [super init]

深入了解 [super init]

作者: Norld | 来源:发表于2017-03-16 14:25 被阅读0次

    原地址: 个人博客 -- 深入了解 [super init]

    开始

    创建一个 Test 测试类, 重写初始化方法:

    - (instancetype)init {
       self = [super init];
       if (self) {
           // do something...
       }
       return self;
    }
    

    疑问:

    • 为何要执行 [super init] ?
    • [super init] 的结果为何要 self 接收?

    探索:

    • [super init]

    这一句看起来很有迷惑性, 一个 super 关键字, 好像初始化的是父类, 但在码代码的时候可以注意一个细节: 在写 self 时, 代码提示是有返回值类型的, 而写 [super init] 时, 并没有返回值类型, 但在别处写 super 时, 自动提示的返回值类型是父类.

    这表示在 [super init] 这句话中, super 并不是指父类, 可能只是一个没有什么卵用的关键字, 但在苹果的官方文档中, 这么写是推荐的写法, 那么这句话就很关键了.

    通过 clang -rewrite-objc Test.m 命令, 重新编译成 cpp 文件, 可以看到这一行代码究竟做了什么:

    static instancetype _I_Test_init(Test * self, SEL _cmd) {
        self = ((Test *(*)(__rw_objc_super *, SEL))(void *)objc_msgSendSuper)((__rw_objc_super){(id)self, (id)class_getSuperclass(objc_getClass("Test"))}, sel_registerName("init"));
        if (self) {
    
        }
        return self;
    }
    

    经过简化后, [super init] 就变为

    objc_msgSendSuper({self, class_getSuperclass(objc_getClass("Test"))}, sel_registerName("init"));
    

    而其中 objc_msgSendSuper() 这个方法, API 文档是这样描述的:

    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 的结构为:

    struct objc_super {
        __unsafe_unretained id receiver;
        __unsafe_unretained Class super_class;
    };
    

    receiver 是实例对象, super_class 是用来接收消息的类, 为实例对象的父类.

    在当前的代码里, receiverself , super_classNSObject .

    再回过头来, 注意看 [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.

    相关文章

      网友评论

        本文标题:深入了解 [super init]

        本文链接:https://www.haomeiwen.com/subject/kpcjnttx.html