iOS开发过程中我们经常会碰到这样的报错:
unrecognized selector sent to instance **,我们调用了一个不存在的方法。
用OC消息机制来说就是:消息的接收者不过到对应的selector,这样就启动了消息转发机制。
抛出异常之前消息转发过程中的步骤:
1.(动态方法解析)询问是否有动态添加方法来进行处理
+(BOOL)resolveInstanceMethod:(SEL)sel
void speak(id self, SEL _cmd,NSSting *msg){
NSLog(@"Now I can speak.%@",msg);
}
+ (BOOL)resolveInstanceMethod:(SEL)sel {
NSLog(@"resolveInstanceMethod: %@", NSStringFromSelector(sel));
if (sel == @selector(speak)) {
#动态添加方法
return class_addMethod([self class], sel, (IMP)speak, "V@:@");
}
return [super resolveInstanceMethod:sel];
}
class_addMethod方法动态添加了一个speak的实现方法来解决掉这条未知的消息,
此时消息转发过程提前结束。
2.(快速转发)询问是否有别的类实现该方法
- (id)forwardingTargetForSelector:(SEL)aSelector
- (id)forwardingTargetForSelector:(SEL)aSelector {
NSLog(@"forwardingTargetForSelector: %@", NSStringFromSelector(aSelector));
Bird *bird = [[Bird alloc] init];
if ([bird respondsToSelector: aSelector]) {
return bird;
}
return [super forwardingTargetForSelector: aSelector];
}
// Bird.m
- (void)fly {
NSLog(@"I am a bird, I can fly.");
}
其它类能实现相应方法,则返回相应实例响应对应方法,消息转发提前结束。
3. 调用签名方法并转发
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
- (void)forwardInvocation:(NSInvocation *)anInvocation
调用forwardInvocation方法前先调用方法签名
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
NSLog(@"method signature for selector: %@", NSStringFromSelector(aSelector));
if (aSelector == @selector(code)) {
return [NSMethodSignature signatureWithObjCTypes:"V@:@"];
}
return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation {
NSLog(@"forwardInvocation: %@", NSStringFromSelector([anInvocation selector]));
if ([anInvocation selector] == @selector(code)) {
Monkey *monkey = [[Monkey alloc] init];
[anInvocation invokeWithTarget:monkey];
} else{
[supre forwardInvocation:anInvocation];
}
}
signatureWithObjCTypes
第一个表示返回值类型,例如:@为id类型,v为void类型
第二个表示函数调用者类型self,即为id类型。一般表示为@
第三个表示SEL方法选择器,一般表示为:冒号。
第四个表示参数类型。例如:i表示int类型
#获取类型编码字符串
NSLog(@"id 类型的编码是:%s",@encode(id)); //@
4. 最后都不能处理,进入Crash
- (void)doesNotRecognizeSelector:(SEL)aSelector{
NSLog(@"找不到方法");
}
网友评论