处理unrecognized selector异常原因

假如封装一个方法,在其他模块调用该方法时,传入参数不匹配则crash。比如下面的方法:本应该传入的参数类型为NSMutableArray,如果传入的参数类型是NSArray,导致抛出 unrecognized selector异常

1
2
3
- (void)doSomethingWithArray:(NSMutableArray *)arr{
[arr addObject:@"123"];
}

当然,通过 参数类型判断 也可以避免问题的发生:

1
2
3
4
5
6
7
- (void)doSomethingWithArray:(NSMutableArray *)arr{
if ([arr isKindOfClass:[NSMutableArray class]]) {
[arr addObject:@"123"];
}else{
CrashOnSimulator(@"⚠️参数类型不对哦⚠️");
}
}

crash提醒:

1
2
3
void CrashOnSimulator(NSString *errorMsg) {
if((TARGET_OS_SIMULATOR)){raise(SIGSTOP);}
}

但是,有点地方可能忘记类型判断了怎么办,有全局拦截unrecognized selector 异常的方案吗?

分析 如何全局拦截unrecognized selector 异常

oc的消息发送机制咱们都熟悉了,通过superclass指针逐级向上查找该消息所对应的方法实现,如果遇到找不的方法,还有三次补救机制。我们可以通过上面三种方法中的一种,就可以避免unrecognized selector sent to instance

第一种方法:重写 NSObject 的forwardingTargetForSelector:

⚠️filter unrecoginze seletor of intance only

思路

  • 创建一个接收未知消息的类,暂且称之为Protector
  • 创建一个NSObject 的分类,在分类中重写forwardingTargetForSelector: ,在这个方法中截获未实现的方法,转发给Protector。并为Protector 动态的添加未实现的方法,最后返回Protector 的实例对象。
  • 在分类中新增一个安全的方法实现,来作为Protector 接收到的未知消息的实现

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
#import "NSObject+Protector.h"
#import <objc/runtime.h>
@implementation NSObject (Protector)
 
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wobjc-protocol-method-implementation"
- (id)forwardingTargetForSelector:(SEL)aSelector{
 
if ([self isCurrentClassInWhiteList]) {
[[self class] warningDeveloper:aSelector];
 
Class protectorCls = NSClassFromString(@"ProtectorClassName");
if (!protectorCls){
protectorCls = objc_allocateClassPair([NSObject class], "ProtectorClassName", 0);
objc_registerClassPair(protectorCls);
}
 
if (![self isExistSelector:aSelector inClass:protectorCls]){
class_addMethod(protectorCls, aSelector, [self safeImplementation:aSelector],[NSStringFromSelector(aSelector) UTF8String]);
}
 
Class Protector = [protectorCls class];
id instance = [[Protector alloc] init];
return instance;
} else {
return nil;
}
}
#pragma clang diagnostic pop
 
- (BOOL)isCurrentClassInWhiteList{
NSArray *classNameArray = @[@"NSNull",@"NSString",@"NSArray",@"NSDictionary",@"NSURL"];
for (NSString *className in classNameArray) {
if ([self isKindOfClass:NSClassFromString(className)]) {
return YES;
}
}
return NO;
}
 
- (BOOL)isExistSelector: (SEL)aSelector inClass:(Class)currentClass{
BOOL isExist = NO;
unsigned int methodCount = 0;
Method *methods = class_copyMethodList(currentClass, &methodCount);
for (int i = 0; i < methodCount; i++){
Method temp = methods[i];
SEL sel = method_getName(temp);
NSString *methodName = NSStringFromSelector(sel);
if ([methodName isEqualToString: NSStringFromSelector(aSelector)]){
isExist = YES;
break;
}
}
return isExist;
}
 
- (IMP)safeImplementation:(SEL)aSelector{
IMP imp = imp_implementationWithBlock(^(){
NSLog(@"PROTECTOR: %@ Done", NSStringFromSelector(aSelector));
});
return imp;
}
 
+ (void)warningDeveloper:(SEL)aSelector{
#if DEBUG
NSString *selectorStr = NSStringFromSelector(aSelector);
NSLog(@"PROTECTOR: -[%@ %@]", [self class], selectorStr);
NSLog(@"PROTECTOR: unrecognized selector \"%@\" sent to instance: %p", selectorStr, self);
NSLog(@"PROTECTOR: call stack: %@", [NSThread callStackSymbols]);
// @throw @"方法找不到";
#endif
}
 
@end

第二种方法:重写 NSObject 的methodSignatureForSelector(有些问题,下面有个最终版)

预防 app crash 之 unrecognized selector的更多相关文章

  1. reason: -[UIKBBlurredKeyView candidateList]: unrecognized selector sent to instance

    reason: -[UIKBBlurredKeyView candidateList]: unrecognized selector sent to instance 发现上线的app一直会有这个cr ...

  2. ios unrecognized selector sent to instance出现的原因和解决方案

    概述:造成unrecognized selector sent to instance iphone,大部分情况下是因为对象被提前release了,在你心里不希望他release的情况下,指针还在,对 ...

  3. 出现“unrecognized selector sent to instance”问题原因之一及解决方法。

      ​ 对于iPhone开发初学者来说,很想实现自己在iPhone上的第一个小程序,准备工作就绪侯就信心满满的开始了!一般来说大家可能都是从Hello World做起吧. 反正我是的,:),如果按照文 ...

  4. [NSNull intValue]: unrecognized selector sent to instance 0x375c9860

    今天遇到这个问题,程序崩溃了……日志如下: -[NSNull intValue]: unrecognized selector sent to instance 0x375c9860*** Termi ...

  5. IOS 错误 [UIWebView cut:]: unrecognized selector sent to instance

    那在什么场景中会出现这种情况呢? 如果一个包含文字的输入元素有焦点,然后按钮的点击会导致输入失去焦点,然后接下来在输入时双按会重新得到焦点并从弹出bar中选择剪切复制粘贴,就会导致此error. 也就 ...

  6. iOS 程序报错:reason: [NSArrayI addObject:]: unrecognized selector sent to instance

    *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSArrayI ad ...

  7. unrecognized selector sent to instance 0x10b34e810

    一个错误: *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSURLEr ...

  8. Solve Error: 'NSInvalidArgumentException', reason: '-[UITableView mas_makeConstraints:]: unrecognized selector sent to instance 0x7fa5c402fa00'

    下面是iOS开发用第三方库可能出现的错误,及其解决方法: 1. 'NSInvalidArgumentException', reason: '-[UITableView mas_makeConstra ...

  9. __NSArrayI removeObjectAtIndex:]: unrecognized selector sent to instance

    同样是删除cell问题,帮我看看问题出现在哪,谢谢! 我的类文件myFile是继承UIViewController的(目的是为了能够在一个view里切换不同的tableView),在myFile.h中 ...

随机推荐

  1. Mysql查询出所有列名

    select group_concat(COLUMN_NAME Separator ',') as COLUMN_NAME from information_schema.COLUMNS where ...

  2. python3安装pip3的方法

    1.点击链接:https://bootstrap.pypa.io/get-pip.py,并下载get-pip.py文件; 2.文件下载完成之后,cd到当前目录,并进行安装,如下: root@zhuzh ...

  3. 036 关于网站的UV分析

    一:准备 1.统计的维度 guid tracktime provice 2.key与value的设定 key:date+provice_guid value:NullWritable 3.案例分析 表 ...

  4. 谈谈MySQL无法连接的原因和分析方法

    [可能的原因] MySQL无法连接的原因有很多,比如: 1.数据库的请求量突增,实例连接数超过max_connections,或用户连接数超过max_user_connections, 这种情况连接时 ...

  5. 我们为什么要学习 Spring Boot

    现在貌似大家都知道 Spring Boot 很火了,做 Java 的不知道 Spring Boot 的都已经 Out 了,但是又有多少人是跟风学习的呢?今天我们就来说一下为什么要学习 Spring B ...

  6. Alpha冲刺随笔三:第三天

    课程名称:软件工程1916|W(福州大学) 作业要求:项目Alpha冲刺(十天冲刺) 团队名称:葫芦娃队 作业目标:在十天冲刺里对每天的任务进行总结. 随笔汇总:https://www.cnblogs ...

  7. 洛谷.3121.审查(AC自动机 链表)

    题目链接 //删掉一个单词需要前移一段位置,用链表维护就好了 复杂度O(sum(len)) #include <cstdio> #include <cstring> #defi ...

  8. Codeforces.100633J.Ceizenpok's formula(扩展Lucas)

    题目链接 ->扩展Lucas //求C_n^k%m #include <cstdio> typedef long long LL; LL FP(LL x,LL k,LL p) { L ...

  9. Android弹出Toast工具类总结

    Android弹出Toast工具类总结,包括系统自带的,也包括自定义的. public class ToastUtil { public ToastUtil() { } public static T ...

  10. bzoj 3450 期望分数

    自己只能想到O(n^2)的: dp[i][j] 表示 以i结尾,长度为j的o串的概率,然后在每次遇到x的时候算分数. 正解是: dp[i]表示前i个的答案,d[i]表示以i结尾的期望长度. 推的时候它 ...