什么時候會報 unrecognied selector異常抠藕?
1、當(dāng)調(diào)用對象(子類诗箍、各級父類)中不含有對應(yīng)方法的時候鳖敷,并且依舊沒有給出“消息轉(zhuǎn)發(fā)”的具體方案的時候脖苏,程序在運行時會crash并拋出 unrecognized selector 異常
2、運行時會根據(jù)對象的isa指針找到該對象所對應(yīng)的類定踱,然后會依次在對應(yīng)的類棍潘、父類、爺爺類崖媚、根類中找對應(yīng)的方法
但在崩潰前亦歉,objc的運行時會給出三次拯救程序崩潰的機(jī)會,
流程圖如下:
根類NSObject提供了重定向方法畅哑,如圖:
1肴楷、+ (BOOL)resolveInstanceMethod:(SEL)sel
指定是否動態(tài)添加方法。若返回NO荠呐,則進(jìn)入下一步赛蔫,若返回YES,則通過class_addMethod()函數(shù)動態(tài)地添加方法泥张,消息得到處理呵恢,此流程完畢。
// 一. 動態(tài)方法解析
+ (BOOL)resolveInstanceMethod:(SEL)sel {
NSLog(@"sel = %@", NSStringFromSelector(sel));
//1.判斷沒實現(xiàn)方法, 就動態(tài)添加方法
if (sel == @selector(run)) {
// 動態(tài)添加方法 IMP(函數(shù)指針)
class_addMethod(self, sel, (IMP)runNew, "v@:");
return YES;
}
// 2.動態(tài)添加的方法沒有使用, 就給super
return [super resolveInstanceMethod:sel];
}
2媚创、- (id)forwardingTargetForSelector:(SEL)aSelector
在第一步返回NO時渗钉,會進(jìn)入該方法,這是運行時給我們的第二次機(jī)會钞钙,用于指定哪個對象響應(yīng)這個selector鳄橘,不能指定為self。若返回nil歇竟,表示沒有響應(yīng)者挥唠,則會進(jìn)入第三步。若返回某個對象焕议,則會調(diào)用該對象的方法。
// 二. 消息轉(zhuǎn)發(fā)重定向
- (id)forwardingTargetForSelector:(SEL)aSelector {
NSLog(@"sel2 = %@", NSStringFromSelector(aSelector));
return [[LKAnimation alloc] init];
}
3弧关、- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
若第二步返回nil盅安,會進(jìn)入該方法。這是運行時提供給我們的第三次補(bǔ)救機(jī)會世囊。指定方法簽名别瞭,若返回nil,則表示不處理株憾。若返回方法簽名蝙寨,則會進(jìn)入下一步晒衩。
// 三.生成方法簽名
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
// 1. 轉(zhuǎn)化成字符串
NSString *sel = NSStringFromSelector(aSelector);
// 2. 判斷
if([sel isEqualToString:@"run"]) {
}
return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}
4、- (void)forwardInvocation:(NSInvocation *)anInvocation
若第三步返回方法簽名后墙歪,則會調(diào)用該方法听系。我們通過anInvocation對象做很多處理,比如修改實現(xiàn)方法虹菲、修改響應(yīng)對象等
// 四.方法的簽名配發(fā)
- (void)forwardInvocation:(NSInvocation *)anInvocation {
NSLog(@"---%@--",anInvocation);
// 1. 拿到消息
SEL selector = [anInvocation selector];
// 2. 轉(zhuǎn)發(fā)消息
Animation *anm = [[Animation alloc] init];
if ([anm respondsToSelector:selector]) {
// 調(diào)用這個對象, 去進(jìn)行轉(zhuǎn)發(fā)
[anInvocation invokeWithTarget:anm];
} else {
[super forwardInvocation:anInvocation];
}
}
5靠胜、- (void)doesNotRecognizeSelector:(SEL)aSelector
若沒有實現(xiàn)- (void)forwardInvocation:(NSInvocation *)anInvocation方法,則會進(jìn)入該方法毕源。若我們沒有實現(xiàn)該方法浪漠,則程序就會crash并拋出 unrecognized selector 異常。至此霎褐,動態(tài)解析的流程就結(jié)束了址愿。
// 五.拋出異常
- (void)doesNotRecognizeSelector:(SEL)aSelector {
NSString *selectorStr = NSStringFromSelector(aSelector);
NSLog(@"這個--%@---方法不存在", selectorStr);
}