需求1、当项目中,需要继承某一个父类,但是父类中并没有提供我们需要的调用方法,一般情况下,这种时候,我们可能会再派生一个类,或者会直接为这个类写一个分类(category),在这个分类中,我们可以新增或者替换某个方法(注意:不推荐在分类中重写方法,而且也无法通过 super 来获取所谓父类的方法)。大致在这两种情况下,我们可以通过 class_addMethod 来实现我们想要的效果。
OC在向一个对象发送消息时,runtime库会根据对象的isa指针找到该对象实际所属的类,然后在该类中的方法列表以及其父类方法列表中寻找方法运行,如果在最顶层的父类中依然找不到相应的方法时,程序在运行时会挂掉并抛出异常unrecognized selector sent to XXX 但是在这之前,OC的运行时会给出三次拯救程序崩溃的机会
//新的 run 函数 void runMethod(idself, SEL _cmd, NSNumber *meter) { NSLog(@"跑了%@", meter); }
Fast forwarding(消息接受者重定向) 如果目标对象实现了-forwardingTargetForSelector:,Runtime这时就会调用这个方法,给你把这个消息转发给其他对象的机会。只要这个方法返回的不是nil和self,整个消息发送的过程就会被重启,当然发送的对象会变成你返回的那个对象。否则,就会继续Normal Fowarding。 这里叫Fast,只是为了区别下一步的转发机制。因为这一步不会创建任何新的对象,但下一步转发会创建一个NSInvocation对象,所以相对更快点
1 2 3 4 5 6 7 8
// 消息接受者重定向 - (id)forwardingTargetForSelector:(SEL)aSelector{ if (aSelector == @selector(run:)) { return [[Person alloc] init]; // 返回 Person 对象,让 Person 对象接收这个消息 } return [super forwardingTargetForSelector:aSelector]; }
Normal forwarding(消息重定向) 这一步是Runtime最后一次给你挽救的机会。首先它会发送-methodSignatureForSelector:消息获得函数的参数和返回值类型。如果-methodSignatureForSelector:返回nil,Runtime则会发出-doesNotRecognizeSelector:消息,程序这时也就挂掉了。如果返回了一个函数签名,Runtime就会创建一个NSInvocation对象并发送-forwardInvocation:消息给目标对象