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 所指代的方法。

  • 相关阅读:
    C++
    C语言获取系统时间的几种方式
    我在学习编程中犯的两个最大错误
    《十天学会单片机和C语言编程》
    socket 编程通信实例
    比尔·盖茨给年轻人的十一个忠告 句句是哲理
    程序员有八个级别。
    DOS debug 命令的详细用法
    从命令行模式运行Windows管理工具。
    无法删除DLL文件解决方法(转)
  • 原文地址:https://www.cnblogs.com/guchengfengyun/p/4054879.html
Copyright © 2011-2022 走看看