美文网首页
Runtime的工作原理(二)

Runtime的工作原理(二)

作者: Kenter_Huang | 来源:发表于2018-10-05 15:34 被阅读5次

    接着前面的说,之前说了runtime的交互、runtime的消息机制、传递、方法地址获取。

    四、Dynamic Method Resolution

      动态方法解析,就是runtime提供了给类动态添加方法的实现。比如类的属性,会自动添加setter和getter方法就是如此,在编译时,将动态的添加与该属性相关联的setter和getter方法。
     可以通过实现这些方法resolveInstanceMethod:resolveClassMethod:,并分别为实例和类方法动态提供给定选择器的实现。

    /// C函数,本身就是一个IMP指针
    void dynamicMethodIMP(id self,SEL _cmd){
        //实施....
    }
    
    @implementation MyClass
    +(BOOL)resolveInstanceMethod:(SEL)aSEL
    {
        if(aSEL == @selector(resolveThisMethodDynamically)) {
              class_addMethod([self class], aSEL, (IMP)dynamicMethodIMP, “v@:”);
              return YES;
        }
        return [super resolveInstanceMethod:aSEL];
    }
    @end
    

    我们看到,动态添加方法使用C函数:

    class_addMethod(Class _Nullable cls, SEL _Nonnull name, IMP _Nonnull imp, const char * _Nullable types);
    

    第一个参数是类,即当前对象的类。
    第二个是一个方法选择器,我理解就是一个方法名。
    第三个是一个指向实现的函数指针,如果是C函数直接强转即可,如果是OC方法,则需要获取。可以使用以下方法获取:

    IMP imp = class_getMethodImplementation([receiver class], @selector(message));
    或者
    Method m = class_getInstanceMethod([receiver class], @selector(message));
    IMP imp = method_getImplementation(m);
    

    第四个是方法的编码,一组描述方法、返回值及参数类型特征的字符。
      比如加入的方法是int sum(id self, SEL _cmd, int a, int b),那么这里是:class_addMethod([receiver class], @selector(sum), (IMP) sum, "i@:ii");i表示int(An int,返回值类型),@表示self(An object,Object类型),:表示_cmd(A method selector (SEL),方法选择器类型),ii分别表示后面两个参数(An int,int类型)。这里苹果有提供一个类型对照表:

    image.png image.png
    通常消息转发和动态方法解析是互不相干的。在进入消息转发机制之前, respondsToSelector:和instancesRespondToSelector: 会被首先调用。您可以在这两个 方法中为传进来的选标提供一个IMP。如果您实现了resolveInstanceMethod:方法但是仍然希望正 常的消息转发机制进行,您只需要返回NO就可以了。
    

    Dynamic Loading

    动态加载可以用在很多地方。例如,系统配置中的模块就是被动态加载的。
    在 Cocoa 环境中,动态加载一般被用来对应用程序进行定制。您的程序可以在运行时加载其他程序员编写 的模块——和 Interface Build 载入定制的调色板以及系统配置程序载入定制的模块的类似。 这些模块通过 您许可的方式扩展了您的程序,而您无需自己来定义或者实现。您提供了框架,而其它的程序员提供了实 现。
    尽管已经有一个运行时系统的函数来动态加载Mach-O文件中的Objective-C模块 (objc_loadModules,在objc/objc-load.h中定义),Cocoa的NSBundle类为动态加载 提供了一个更方便的接口——一个面向对象的,已和相关服务集成的接口。关于NSBundle类的更多相关
    信息请参考Foundation框架中关于NSBundle类的文档。关于Mach-O文件的有关信息请参考Mac OS X ABI Mach-O 文件格式参考库。
    

    五、Message Forwarding

    通常,给一个对象发送它不能处理的消息会得到出错提示,然而,Objective-C 运行时系统在抛出错误之前, 会给消息接收对象发送一条特别的消息来通知该对象。这就是消息转发。

    如果一个对象收到一条无法处理的消息,运行时系统会在抛出错误前,给该对象发送一条
    forwardInvocation:消息,该消息的唯一参数是个 NSInvocation 类型的对象——该对象封装了 原始的消息和消息的参数。
    您可以实现 forwardInvocation:方法来对不能处理的消息做一些默认的处理,也可以以其它的某种 方式来避免错误被抛出。如 forwardInvocation:的名字所示,它通常用来将消息转发给其它的对象。
    

    相关文章

      网友评论

          本文标题:Runtime的工作原理(二)

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