
1、動態(tài)方法解析
對象在收到無法處理的消息時,會調(diào)用下面的方法,前者是調(diào)用類方法時會調(diào)用,后者是調(diào)用對象方法時會調(diào)用。
// 類方法專用
+ (BOOL)resolveClassMethod:(SEL)sel
// 對象方法專用
+ (BOOL)resolveInstanceMethod:(SEL)sel
在該方法中,需要給對象所屬類動態(tài)的添加一個方法,并返回YES,表明可以處理
void dynamicMethodIMP(id self, SEL _cmd) { ? ?
????NSLog(@" >> dynamicMethodIMP");
}
+ (BOOL)resolveInstanceMethod:(SEL)sel { ? ?
????NSLog(@"%@", NSStringFromSelector(sel)); ? ?
????if (sel == @selector(run)) { ? ? ? ?
????????class_addMethod([self class], sel, (IMP)dynamicMethodIMP, "v@:"); ? ? ? ?
????????return YES; ? ?
? ? ? ?} ? ?
????return [super resolveInstanceMethod:sel];
}
2、備援接受者
經(jīng)歷了第一步后,如果該消息還是無法處理,那么就會調(diào)用下面的方法,查詢是否有其它對象能夠處理該消息。
- (id)forwardingTargetForSelector:(SEL)aSelector
在這個方法里,我們需要返回一個能夠處理該消息的對象
- (id)forwardingTargetForSelector:(SEL)aSelector { ? ?
????NSLog(@"%@", NSStringFromSelector(aSelector)); ? ?
????if (aSelector == @selector(run)) { ? ? ? ?
????????Animal *animal = [[Animal alloc] init]; ? ? ? ?
????????return animal; ? ?
????} ? ?
????return [super forwardingTargetForSelector:aSelector];
}
3、完整的消息轉(zhuǎn)發(fā)
經(jīng)歷了前兩步,還是無法處理消息,那么就會做最后的嘗試,先調(diào)用methodSignatureForSelector:獲取方法簽名,然后再調(diào)用forwardInvocation:進行處理,這一步的處理可以直接轉(zhuǎn)發(fā)給其它對象,即和第二步的效果等效,但是很少有人這么干,因為消息處理越靠后,就表示處理消息的成本越大,性能的開銷就越大。所以,在這種方式下,會改變消息內(nèi)容,比如增加參數(shù),改變選擇子等等。
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
- (void)forwardInvocation:(NSInvocation *)anInvocation
下面是改變選擇子的例子
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { ? ? ????NSLog(@"%@", NSStringFromSelector(aSelector)); ? ?
????if (aSelector == @selector(run)) { ? ? ? ?
????????NSMethodSignature *signature = [NSMethodSignature signatureWithObjCTypes:"v@:"]; ? ? ? ?
????????return signature; ? ?
????} ? ?
????return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation { ? ?
????NSLog(@"%@", anInvocation); ? ?
????NSMethodSignature *signature = [NSMethodSignature signatureWithObjCTypes:"v@:"]; ? ? ????anInvocation = [NSInvocation invocationWithMethodSignature:signature]; ? ?
????[anInvocation setSelector:@selector(runNew)]; ? ?
????????if ([self respondsToSelector:@selector(runNew)]) { ? ? ? ?
????????[anInvocation invokeWithTarget:self]; ? ? ? ?
????????return; ? ?
????} else { ? ? ? ?
????????Animal *s = [[Animal alloc] init]; ? ? ? ?
? ? ? ?if ([s respondsToSelector:anInvocation.selector]) { ? ? ? ? ? ?
????????????[anInvocation invokeWithTarget:s]; ? ? ? ? ? ?
????????????return; ? ? ? ?
????????} ? ?
????} ? ?
????[super forwardInvocation:anInvocation];
}
- (void)runNew { ? ?
????NSLog(@"runNewrunNewrunNew");
}