深入学习runtime

作者: Sunxb | 来源:发表于2019-02-22 17:20 被阅读8次

    本文的切入点是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


    (未完待续)

    相关文章

      网友评论

        本文标题:深入学习runtime

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