001 runtime实质
Runtime 就是去解决如何在运行时期找到调用方法这样的问题。
Runtime 的核心就是 objc_msgSend 函数,通过给类发送 SEL 以传递消息,找到匹配的 IMP 再获取最终的实现。
O(1)复杂度
对于实例变量有如下的思路:
instance -> class -> method -> SEL -> IMP -> 实现函数‘
002 消息传递
向一个对象发送消息时,Runtime 会根据实例对象的 isa 指针找到其所属的类,并自底向上直至根类(NSObject)中 去寻找 SEL 所对应的方法,找到后就运行整个方法。
metaClass是元类,也有 isa 指针、super_class 指针。其中保存了类方法列表。
IMP 可以理解为函数指针,指向了最终的实现。
SEL 与 IMP 的关系非常类似于 HashTable 中 key 与 value 的关系。OC 中不支持函数重载的原因就是因为一个类的方法列表中不能存在两个相同的 SEL 。但是多个方法却可以在不同的类中有一个相同的 SEL,不同类的实例对象执行相同的 SEL 时,会在各自的方法列表中去根据 SEL 去寻找自己对应的IMP。这使得OC可以支持函数重写。
003 动态消息解析
1.通过resolveInstanceMethod得知方法是否为动态添加,YES则通过class_addMethod动态添加方法处理消息。
2.这步会进入forwardingTargetForSelector进行用于指定那个对象来响应消息,如果返回nil进入3步,传递给指定对象有着比较高的效率。
3.这步调用methodSignatureForSelector进行方法签名,这可以将函数的参数类型和返回值进行封装,如果返回 nil 说明消息无法处理并报错 unrecognized selector sent to instance
,如果返回methodSignature则进入forwardInvocation 这里可以修改实现方法,修改响应对象等。如果方法调用成功,则结束。如果依然不能正确响应消息,则报错 unrecognized selector sent to instance
.
2,3步骤中实现对接受对象的转移,可以实现“多重继承”的效果