RunTime-简称运行时。就是系统在运行的时候的有些机制,其中最主要的就是消息机制。
对于C语言来说,函数的调用在编译的时候就会决定调用哪一个函数。编译完成之后,将会直接顺序执行,无任何的二义性。而OC到底函数调用为消息发送,属于动态调用过程。
在编译的时候并不能决定真正调用哪个函数(事实证明,在编 译阶段,OC可以调用任何函数,即使这个函数并未实现,只要申明过就不会报错。而C语言在编译阶段就会报错)。只有在真正运行的时候才会根据函数的名称找 到对应的函数来调用。
以下为OC 的动态调用:假如OC中有个这样的代码:
[obj makeText];
其中obj是一个对象,makeText是一个函数名称。对于这样一个简单的调用。在编译时RunTime会将上述代码转化成
objc_msgSend(obj,@selector(makeText));
任何一个方法,都是转换上面的这个C函数,当我去调用一个方法,如果我在当前的类中没有寻找到,我将会去父类中进行寻找,一层层往上找。如果我找到了,我将会把这个函数放在这个类中的缓存表(加快访问和调用,防止每一次都去分发表当中寻找,因为这样很耗时)当中;如果还是没有找到,就会启用消息转发,然后动态添加进去
eg:
void minus(id self, SEL _cmd, NSNumber *val){
NSLog(@"Hello World, %f", [val floatValue]);
}
- (void)test:(SEL)sel{
if(sel == @selector(minus:)){
class_addMethod([self class], sel, (IMP)minus, "v@":f"");
}
}
动态 vs 静态语言
Objective-C 是面相运行时的语言(runtime oriented language),就是说它会尽可能的把编译和链接时要执行的逻辑延迟到运行时。这就给了你很大的灵活性,你可以按需要把消息重定向给合适的对象,你甚 至可以交换方法的实现,等等(译注:在 Objective-C 中调用一个对象的方法可以看成向一个对象发送消息, Method Swizzling 具体实现可以参看 jrswizzle )。这就需要使用 runtime,runtime 可以做对象自省查看他们正在做的和不能做的(don’t respond to)并且合适的分发消息(译注:感兴趣的同学可以查看 NSObject 类的 – forwardingTargetForSelector: 和 – forwardInvocation: 方法。P.S. 不是 NSObject 协议! )。如果我们和 C 这样的语言对比。在 C 里,你从 main() 方法开始写然后就是从上到下的写逻辑了并按你写代码的顺序执行程序。一个 C 的结构体不能转发函数执行请求到其他的目标上(other targets)。