如何防止unrecognized selector sent to instance 0xxx引起的崩潰問題

在開發(fā)中經(jīng)常遇到一種錯誤,就是unrecognized selector sent to instance ***,這種類型的錯誤,說簡單點,就是找不到這個類所對應的方法,這種情況通常是因為開發(fā)者的粗心,比如忘記了寫按鈕的方法實現(xiàn),或者是服務器數(shù)據(jù)錯誤而引起的。
之前有人針對開發(fā)中常見的一些崩潰問題做過處理,但是僅限于數(shù)組越界,字典key值為空之類的常見錯誤,比如
這個項目。但是針對未識別方法的崩潰處理,這個項目里是沒有的,所以我現(xiàn)在做的這個也算是對他的一種補充吧。
在demo中我們創(chuàng)建了一個紅色的btn

  [btn addTarget:self action:@selector(click) forControlEvents:UIControlEventTouchUpInside];

但是并沒有實現(xiàn)click這個方法,所以再點擊按鈕后,很自然的崩潰了。如下圖

錯誤信息.png

當對崩潰方法進行轉(zhuǎn)發(fā)處理后,就不會崩潰了。而是會彈出一個彈框,告訴我們哪個類的什么方法沒有找到。在DEBUG模式中,也方便開發(fā)者調(diào)試。

下面是方法轉(zhuǎn)發(fā)的關(guān)鍵代碼:

#import "NSObject+UnRecognizedSelHandler.h"
#import <objc/runtime.h>

//提示框--->UIAlertController
#define ALERT_VIEW(Title,Message,Controller) {UIAlertAction *action = [UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleDefault handler:nil];UIAlertController *alertVc = [UIAlertController alertControllerWithTitle:Title message:Message preferredStyle:UIAlertControllerStyleAlert];        [alertVc addAction:action];[Controller presentViewController:alertVc animated:YES completion:nil];}

#import "AppDelegate.h"
static NSString *_errorFunctionName;
void dynamicMethodIMP(id self,SEL _cmd){
#ifdef DEBUG
    AppDelegate *delegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
    UIViewController *currentRootViewController = delegate.window.rootViewController;
    NSString *error = [NSString stringWithFormat:@"errorClass->:%@\n errorFuction->%@\n errorReason->UnRecognized Selector",NSStringFromClass([self class]),_errorFunctionName];
    ALERT_VIEW(@"程序異常",error,currentRootViewController);
#else
    //upload error
    
#endif
    
}
#pragma mark 方法調(diào)換
static inline void change_method(Class _originalClass ,SEL _originalSel,Class _newClass ,SEL _newSel){
    Method methodOriginal = class_getInstanceMethod(_originalClass, _originalSel);
    Method methodNew = class_getInstanceMethod(_newClass, _newSel);
    method_exchangeImplementations(methodOriginal, methodNew);
}

@implementation NSObject (UnRecognizedSelHandler)
+ (void)load{
    
    change_method([self class], @selector(methodSignatureForSelector:), [self class], @selector(SH_methodSignatureForSelector:));
    
    change_method([self class], @selector(forwardInvocation:), [self class], @selector(SH_forwardInvocation:));
}

- (NSMethodSignature *)SH_methodSignatureForSelector:(SEL)aSelector{
    if (![self respondsToSelector:aSelector]) {
        _errorFunctionName = NSStringFromSelector(aSelector);
        NSMethodSignature *methodSignature = [self SH_methodSignatureForSelector:aSelector];
        if (class_addMethod([self class], aSelector, (IMP)dynamicMethodIMP, "v@:")) {
            NSLog(@"臨時方法添加成功!");
        }
        if (!methodSignature) {
            methodSignature = [self SH_methodSignatureForSelector:aSelector];
        }
        
        return methodSignature;
        
    }else{
        return [self SH_methodSignatureForSelector:aSelector];
    }
}

- (void)SH_forwardInvocation:(NSInvocation *)anInvocation{
    SEL selector = [anInvocation selector];
    if ([self respondsToSelector:selector]) {
        [anInvocation invokeWithTarget:self];
    }else{
        [self SH_forwardInvocation:anInvocation];
    }
}
@end

原理就是運用oc的運行時,將系統(tǒng)的轉(zhuǎn)發(fā)方法與自己的方法做替換,從而為這個對象重新綁定一個新的方法,新的方法會在當前頁面彈出程序的錯誤信息。也可以在這里將錯誤的代碼信息上傳到自己的服務器中。效果如下:

捕獲到的崩潰信息.png

最后可以點擊這里下載demo。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容