美文网首页
unrecognized selector sent to in

unrecognized selector sent to in

作者: Alfred的记录本 | 来源:发表于2018-01-04 19:57 被阅读0次

    调用方法时,如果在message方法在receiver对象的类继承体系中没有找到方法,那怎么办?一般情况下,程序在运行时就会Crash掉,抛出unrecognized selector sent to…类似这样的异常信息。但在抛出异常之前,还有三次机会按以下顺序让你拯救程序。如下图所示:

    selector.png

    1、在发送消息的对象或其父类中动态增加没有实现的方法(假如没有实现的方法是sendMessage:)。需要在发送消息的对象中重写或其父类(NSObject)中重写+ (BOOL)resolveInstanceMethod:(SEL)sel; / + (BOOL)resolveClassMethod:(SEL)sel;,如果是实例方法会调用resolveInstanceMethod,如果这个方法是一个类方法,就会调用resolveClassMethod。

    + (BOOL)resolveInstanceMethod:(SEL)sel
    {
        if (sel == @selector(sendMessage:)) {
            class_addMethod([self class], sel, imp_implementationWithBlock(^(id self, NSString *word) {
                NSLog(@"method resolution way : send message = %@", word);
            }), "v@*");
        }
    
        return YES;
    }
    

    2、如果如上方法返回NO, 则调用如下方法,并委托其他类进行处理该方法。假如MessageForwarding已经实现了sendMessage:方法。

    - (id)forwardingTargetForSelector:(SEL)aSelector
    {
        if (aSelector == @selector(sendMessage:)) {
            return [MessageForwarding new];
        }
        return nil;
    }
    

    3、如果没有使用Fast Forwarding来消息转发,最后只有使用Normal Forwarding来进行消息转发。它首先调用methodSignatureForSelector:方法来获取函数的参数和返回值,并构造一个NSMethodSignature对象返回,并以此作为forwardInvocation的参数传递给forwardInvocation。如果methodSignatureForSelector返回为nil,程序会Crash掉,并抛出unrecognized selector sent to instance异常信息。如果返回一个函数签名,系统就会创建一个NSInvocation对象并调用-forwardInvocation:方法。

    - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
    {
        NSMethodSignature *methodSignature = [super methodSignatureForSelector:aSelector];
    
        if (!methodSignature) {
            methodSignature = [NSMethodSignature signatureWithObjCTypes:"v@:*"];
        }
    
        return methodSignature;
    }
    
    - (void)forwardInvocation:(NSInvocation *)anInvocation
    {
        MessageForwarding *messageForwarding = [MessageForwarding new];
    
        if ([messageForwarding respondsToSelector:anInvocation.selector]) {
            [anInvocation invokeWithTarget:messageForwarding];
        }
    }
    

    明白了处理逻辑后,可以在如上三个步骤中的任何一个进行处理,这里选择的是在步骤2总进行处理,因为3里面用到了 NSInvocation 对象,此对象性能开销较大,而且这种异常如果出现必然频次较高。最适合将消息转发到一个备用者对象上。

    -(id)forwardingTargetForSelector:(SEL)aSelector{
        HSProtectHandler *protectHandler = [HSProtectHandler new];
     
        class_addMethod([HSProtectHandler class], aSelector, [protectHandler methodForSelector:@selector(handleSelector:)], "v@:");
        return protectHandler;
    }
    

    参考:
    iOS中的unrecognized selector sent to instance
    轻松学习之 Objective-C消息转发
    iOS中的crash防护

    相关文章

      网友评论

          本文标题:unrecognized selector sent to in

          本文链接:https://www.haomeiwen.com/subject/jeilnxtx.html