# Runtime
Runtime 不光能够进行方法交换,还能够在运行时处理 Objective-C 特性相关(比如类、成员函数、继承)的增删改操作。
苹果公司已经开源了 Runtime,在 GitHub 上有可编译的 Runtime 开源版本。你可以通过于德志 (@halfrost) 博客的三篇 Runtime 文章,即 isa 和 Class、消息发送与转发,以及如何正确使用 Runtime,来一边学习一边调试。
直接使用 Runtime 的方法进行方法交换存在的风险
第一个风险是,需要在 +load 方法中进行方法交换。因为如果在其他时候进行方法交换,难以保证另外一个线程中不会同时调用被交换的方法,从而导致程序不能按预期执行。
第二个风险是,被交换的方法必须是当前类的方法,不能是父类的方法,直接把父类的实现拷贝过来不会起作用。父类的方法必须在调用的时候使用,而不是方法交换时使用。
第三个风险是,交换的方法如果依赖了 cmd,那么交换后,如果 cmd 发生了变化,就会出现各种奇怪问题,而且这些问题还很难排查。特别是交换了系统方法,你无法保证系统方法内部是否依赖了 cmd。
a、_ cmd 是隐藏的参数,表示当前方法的selector,他和self表示当前方法调用的对象实例。
b、获取当前被调用方法: NSStringFromSelector(_ cmd)
c、在运行时时使用:在某个分类方法里为对象动态添加属性,由于_cmd是在编译时候(compile - time)就可以确定的值,因此可以直接使用第四个风险是,方法交换命名冲突。如果出现冲突,可能会导致方法交换失败。
ISA指针结构体 方法列表是如何存储
- 对象方法:(保存到类对象的方法列表) ,类方法:(保存到元类(Meta Class)中方法列表)
消息转发
- 对象在收到无法解读的消息后,会调用+(BOOL)resolveInstanceMethod:(SEL)sel或者+ (BOOL)resolveClassMethod:(SEL)sel,询问是否有动态添加方法进行处理
- 没有新增方法,那就看看有没有别人能够帮忙处理- (id)forwardingTargetForSelector:(SEL)aSelector
- 调用- (void)forwardInvocation:(NSInvocation *)anInvocation,在调用forwardInvocation:之前会调用- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector方法来获取这个选择子的方法签名,然后在-(void)forwardInvocation:(NSInvocation *)anInvocation方法中你就可以通过anInvocation拿到相应信息做处理