Runtime的工作原理(二)

接着前面的说,之前说了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类型)。这里苹果有提供一个类型对照表:

Runtime的工作原理(二)_第1张图片
image.png
Runtime的工作原理(二)_第2张图片
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的工作原理(二))