c语言执行函数时使用“静态绑定”,即在程序编译时期就确定了具体的执行函数(知道函数存储地址)。而OC采用的runtime,使用“动态绑定”,在编译时期并没有确定具体执行函数,而是拿到函数的方法名(每个类中有一个表用于存放所有可以调用的方法名,程序运行期间才会根据方法名去查找对应函数地址),并不知道函数存储地址,这就为什么对象可以动态添加方法和属性。
runtime实际是一种“消息发送”机制,为了处理不能识别的消息,还有“消息转发”机制。
当需要调用某个方法时,会使用objc_msgSend(),将方法名传递给接受者,然后接受者会在方法表中查询此方法,这一过程称之为消息发送。而当出现不能识别的方法时,就触发了“消息转发”机制。
1.首先会触发resolveInstanceMethod:(SEL)selector方法(其中selector表示的是不能识别的方法名)。执行此方法是为了确定是否动态为类添加了方法,所以可以在此方法中作第一次异常处理,动态类添加方法(使用class_addMethod())。
2.如果此时没有动态添加的方法,那么就会执行forwardingTargetForSelector:(SEL)selector,这个方法是寻找是否有其它对象可以处理selector(因为内部可能有其它对象可以实现此selector),此时可以作第二次异常处理,需要返回可以处理selector的对象。
3.最后如果依然没有对象可以处理,那么会触发完整的“消息转发”,将selector等信息(包含接受对象、选择子、参数)打包成NSInvocation,触发forwardingInvocation:(NSInvocation*)invocation,此时可以作第三次异常处理。此时需调用超类的同名方法,直致NSObject。这样继承体系中每个类都可以处理此条消息,如果最后都没有处理,那么讲最后触发doesNotRecognizeSelector方法抛出异常。
消息转发示意图:引用《Effective+Objective-C+2.0++编写高质量iOS与OS+X代码的52个有效方法》