zoukankan      html  css  js  c++  java
  • ios底层开发消息机制(二)消息调用过程

    上一章节对基础概念有了些了解,我们对ObjC 中的消息应该有个大致思路了:示例

    Bird * aBird = [[Bird alloc] init];

    [aBird fly];

    中对 fly 的调用,编译器通过插入一些代码,将之转换为对方法具体实现IMP的调用,这个 IMP是通过在 Bird 的类结构中的方法链表中查找名称为fly 的 选标SEL 对应的具体方法实现找到的。

    上面的思路还有一些没有提及的话题,比如说编译器插入了什么代码,如果在方法链表中没有找到对应的 IMP又会如何,这些话题在下面展开。

    消息函数 obj_msgSend:

    编译器会将消息转换为对消息函数 objc_msgSend的调用,该函数有两个主要的参数:消息接收者id 和消息对应的方法选标 SEL, 同时接收消息中的任意参数:

    id objc_msgSend(id theReceiver, SELtheSelector, ...)

    如上面的消息 [aBird fly]会被转换为如下形式的函数调用:

    objc_msgSend(aBird, @selector(fly));

    该消息函数做了动态绑定所需要的一切工作:

    1,它首先找到 SEL 对应的方法实现 IMP。因为不同的类对同一方法可能会有不同的实现,所以找到的方法实现依赖于消息接收者的类型。
    2, 然后将消息接收者对象(指向消息接收者对象的指针)以及方法中指定的参数传递给方法实现 IMP。
    3, 最后,将方法实现的返回值作为该函数的返回值返回。

    编译器会自动插入调用该消息函数objc_msgSend的代码,我们无须在代码中显示调用该消息函数。当objc_msgSend找到方法对应的实现时,它将直接调用该方法实现,并将消息中所有的参数都传递给方法实现,同时,它还将传递两个隐藏的参数:消息的接收者以及方法名称 SEL。这些参数帮助方法实现获得了消息表达式的信息。它们被认为是”隐藏“的是因为它们并没有在定义方法的源代码中声明,而是在代码编译时是插入方法的实现中的。

    尽管这些参数没有被显示声明,但在源代码中仍然可以引用它们(就象可以引用消息接收者对象的实例变量一样)。在方法中可以通过self来引用消息接收者对象,通过选标_cmd来引用方法本身。在下面的例子中,_cmd 指的是strange方法,self指的收到strange消息的对象。

    - strange

    {

        id target = getTheReceiver();

        SEL method = getTheMethod();

        if (target == self || mothod == _cmd)

            return nil;

        return [target performSelector:method];

    }

    在这两个参数中,self更有用一些。实际上,它是在方法实现中访问消息接收者对象的实例变量的途径。

    查找 IMP 的过程:

    前面说了,objc_msgSend 会根据方法选标 SEL 在类结构的方法列表中查找方法实现IMP。这里头有一些文章,我们在前面的类结构中也看到有一个叫objc_cache *cache 的成员,这个缓存为提高效率而存在的。每个类都有一个独立的缓存,同时包括继承的方法和在该类中定义的方法。。

    查找IMP 时:

    1,首先去该类的方法 cache 中查找,如果找到了就返回它;

    2,如果没有找到,就去该类的方法列表中查找。如果在该类的方法列表中找到了,则将 IMP 返回,并将它加入cache中缓存起来。根据最近使用原则,这个方法再次调用的可能性很大,缓存起来可以节省下次调用再次查找的开销。3,3,如果在该类的方法列表中没找到对应的 IMP,在通过该类结构中的 super_class指针在其父类结构的方法列表中去查找,直到在某个父类的方法列表中找到对应的IMP,返回它,并加入cache中。

    4,如果在自身以及所有父类的方法列表中都没有找到对应的 IMP,则进入下文中要讲的消息转发流程。

    便利函数:

    我们可以通过NSObject的一些方法获取运行时信息或动态执行一些消息:

     class   返回对象的类;

     isKindOfClass 和 isMemberOfClass检查对象是否在指定的类继承体系中;

     respondsToSelector 检查对象能否相应指定的消息;

     conformsToProtocol 检查对象是否实现了指定协议类的方法;

     methodForSelector  返回指定方法实现的地址。

     performSelector:withObject 执行SEL 所指代的方法。

  • 相关阅读:
    luogu 1865 数论 线性素数筛法
    洛谷 2921 记忆化搜索 tarjan 基环外向树
    洛谷 1052 dp 状态压缩
    洛谷 1156 dp
    洛谷 1063 dp 区间dp
    洛谷 2409 dp 月赛题目
    洛谷1199 简单博弈 贪心
    洛谷1417 烹调方案 dp 贪心
    洛谷1387 二维dp 不是特别简略的题解 智商题
    2016 10 28考试 dp 乱搞 树状数组
  • 原文地址:https://www.cnblogs.com/guchengfengyun/p/4054879.html
Copyright © 2011-2022 走看看