在開發(fā)中經(jīng)常遇到一種錯誤缩多,就是unrecognized selector sent to instance ***呆奕,這種類型的錯誤,說簡單點瞧壮,就是找不到這個類所對應(yīng)的方法登馒,這種情況通常是因為開發(fā)者的粗心,比如忘記了寫按鈕的方法實現(xiàn)咆槽,或者是服務(wù)器數(shù)據(jù)錯誤而引起的陈轿。
之前有人針對開發(fā)中常見的一些崩潰問題做過處理,但是僅限于數(shù)組越界秦忿,字典key值為空之類的常見錯誤麦射,比如
這個項目。但是針對未識別方法的崩潰處理灯谣,這個項目里是沒有的潜秋,所以我現(xiàn)在做的這個也算是對他的一種補(bǔ)充吧。
在demo中我們創(chuàng)建了一個紅色的btn
[btn addTarget:self action:@selector(click) forControlEvents:UIControlEventTouchUpInside];
但是并沒有實現(xiàn)click這個方法胎许,所以再點擊按鈕后峻呛,很自然的崩潰了。如下圖
錯誤信息.png
當(dāng)對崩潰方法進(jìn)行轉(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ā)方法與自己的方法做替換,從而為這個對象重新綁定一個新的方法色徘,新的方法會在當(dāng)前頁面彈出程序的錯誤信息恭金。也可以在這里將錯誤的代碼信息上傳到自己的服務(wù)器中。效果如下:
捕獲到的崩潰信息.png
最后可以點擊這里下載demo褂策。