OC 是面向运行时的语言。Runtime就是系统在运行的时候的一些机制,其中最主要的是消息发送机制。OC语言与其他语言(如C语言)在函数(方法)的调用有很大的不同。C语言,函数的调用在编译的时候就已经决定调用哪个函数,编译完成之后直接顺序执行。而对于OC言,方法的调用则不然,在编译的时候不决定调用哪个方法。因为OC的方法调用是消息发送,属于动态调用过程,只有在真正运行的时候才会根据方法的名称找到对应的方法来调用。
OC是怎么实现动态调用的呢?
[obj start];
obj是对象,start是方法名。在编译时Runtime会将上述的代码转化为:
1 objc_msgSend(obj,@selector(start));
OC中所有的对象都继承于NSObject
1 @interface NSObject <NSObject> { 2 Class isa OBJC_ISA_AVAILABILITY; 3 }
在NSObject中存在一个Class的isa指针。下面介绍这个Class:
1 struct objc_class { 2 Class isa OBJC_ISA_AVAILABILITY;//指向metaclass 3 4 #if !__OBJC2__ 5 Class super_class OBJC2_UNAVAILABLE;//指向其父类 6 const char *name OBJC2_UNAVAILABLE;//类名 7 long version OBJC2_UNAVAILABLE;//版本号 8 long info OBJC2_UNAVAILABLE;//一些标识信息 9 long instance_size OBJC2_UNAVAILABLE;//该类的实例变量大小 10 struct objc_ivar_list *ivars OBJC2_UNAVAILABLE;//用于存储每个成员变量的地址 11 struct objc_method_list **methodLists OBJC2_UNAVAILABLE;//方法列表 12 struct objc_cache *cache OBJC2_UNAVAILABLE;//指向最近使用的方法的指针 13 struct objc_protocol_list *protocols OBJC2_UNAVAILABLE;//存储该类遵守的协议 14 #endif 15 16 } OBJC2_UNAVAILABLE; 17 /* Use `Class` instead of `struct objc_class *` */
下面我们看一下方法是如何调用的:
首先,编译器将代码[obj start];转化为objc_msgSend(obj, @selector (start));,在objc_msgSend方法中。首先通过obj的isa指针找到obj对应的class。在Class中先去cache中 通过SEL查找对应方法method(猜测cache中method列表是以SEL为key通过hash表来存储的,这样能提高方法查找速度),若 cache中未找到。再去methodList中查找,若methodlist中未找到,则取superClass中查找。若能找到,则将method加 入到cache中,以方便下次查找,并通过method中的函数指针跳转到对应的方法中去执行。