美文网首页
读李峰峰博客笔记之RunTime消息发送

读李峰峰博客笔记之RunTime消息发送

作者: 扑倒的柔情 | 来源:发表于2017-03-17 16:53 被阅读9次

    消息

    • 体会苹果官方文档中的 messages aren’t bound to method implementations until Runtime。消息直到运行时才会与方法实现进行绑定。
      • 我理解的是:源码通过预处理 ->编译->链接->汇编->生成可执行文件,在由shell(暂且理解为shell)解释执行的时候才与方法的实现进行绑定,
      • 如何绑定:如果是实例方法每个实例的isa指针指向该实例对应的类,在这个类中有一个分发表,在这个表中存储着一个SEL(理解为方法编号)对应一个IMP(函数指针),通过SEL找到对应的IMP,再将IP指针指向该函数地址执行

    1、objc_msgSend

    • 这里要清楚一点,objc_msgSend 方法看起来好像返回了数据,其实objc_msgSend 从不返回数据,而是你的方法在运行时** 实现 ** ** 被调用后 **才会返回数据。下面详细叙述消息发送的步骤(如下图):

    消息转发顺序

    1. 首先检测这个* selector *是不是要忽略,比如 Mac OS X 开发,有了垃圾回收就不理会 retain,release 这些函数。
    • 检测这个 selector 的 target 是不是 nil,Objc 允许我们对一个 nil 对象执行任何方法不会 Crash,因为运行时会被忽略掉

    • 如果上面两步都通过了,那么就开始查找这个类的实现 IMP,先从 cache 里查找,如果找到了就运行对应的函数去执行相应的代码。

    • 如果 cache 找不到就找类的方法列表中是否有对应的方法。

    • 如果类的方法列表中找不到就到父类的方法列表中查找,一直找到 NSObject 类为止。

    • 如果还找不到,就要开始进入动态方法解析了

    • 消息转发函数,编译器会根据情况在以下四个方法中选择一个调用

    /** 如果消息是传递给父类,那么会调用名字带有 Super 的函数,如果消息返回值是数据结构而不是简单值时,会调用名字带有 stret 的函数。 */
    objc_msgSend
    objc_msgSend_stret
    objc_msgSendSuper
    objc_msgSendSuper_stret
    

    2、方法中的隐藏参数

    • ** 我们经常用到关键字 self ,但是 self 是如何获取当前方法的对象呢? **
      其实,这也是 Runtime 系统的作用,self 实在方法运行时被动态传入的。当 objc_msgSend 找到方法对应实现时,它将直接调用该方法实现,并将消息中所有参数都传递给方法实现,同时,它还将传递两个隐藏参数:
    • 接受消息的对象(self 所指向的内容,当前方法的对象指针)
    • 方法选择器(_cmd 指向的内容,当前方法的 SEL 指针)
      这两个参数中, self更实用。它是在** 方法实现中 访问 消息接收者对象 的实例变量的 途径 **(不是很理解)

    3、获取方法的地址

    • NSObject 类中有一个实例方法:methodForSelector,你可以用它来获取某个方法选择器对应的 IMP ,举个例子:
    /* 定义一个函数指针 */
    void (*setter)(id, SEL, BOOL);
    int i;
    /* 给函数指针赋值 */
    setter = (void (*)(id, SEL, BOOL))[target methodForSelector:@selector(setFilled:)];
    /* 通过函数指针调用1000次这个方法 */
    for ( i = 0 ; i < 1000 ; i++ ){
        setter(targetList[i], @selector(setFilled:), YES);
    }
    

    ** 注意:上面用到的methodForSelector:方法是由 Runtime 系统提供的,而不是 Objc 自身的特性 **

    相关文章

      网友评论

          本文标题:读李峰峰博客笔记之RunTime消息发送

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