处理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. (第7篇)灵活易用易维护的hadoop数据仓库工具——Hive

    摘要: Hive灵活易用且易于维护,十分适合数据仓库的统计分析,什么样的结构让它具备这些特性?我们如何才能灵活操作hive呢? 博主福利 给大家推荐一套hadoop视频课程 [百度hadoop核心架构 ...

  2. 行为型模式之Command模式

    命令模式将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化, 并且可以对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能. 概念描述 把命令的调用者与执行者分开,使双方不必关心对方是 ...

  3. java集合进行排序的两种方式

    java集合的工具类Collections中提供了两种排序的方法,分别是: Collections.sort(List list) Collections.sort(List list,Compara ...

  4. bzoj 4503

    没有权限号就只能对拍了 我们令?代表的T值=0,然后设出这样一个式子 这样一来,只要T和S在j位置匹配,当且仅当Dj=0,然后我们将这个式子拆开,变成下面那样 思路大概就是这样 最后发现答案应该是在a ...

  5. ubuntu16.04下搜狗输入法异常

    问题描述: 搜狗输入法出现异常, 提示: 删除 .config/Sougou-PY 文件后重启 解决方案: google后发现,搜狗拼音输入法使用 fcitx 框架. 发现系统同时安装了ibus框架 ...

  6. POJ1417 True Liars 并查集 动态规划 (种类并查集)

    欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - POJ1417 题意概括 有一群人,p1个好人,p2个坏人. 他们说了n句话.(p1+p2<=600,n ...

  7. Hat’s Words HDU1247

    一个很经典的字典树题目 先建树 再拆单词进行判断是否都在树内 因为爆内存错了很久 如果一个四十万的数组  用mamset的话会直接爆几十万的内存 所以要:用多少 初始化多少才对!( 修改了两条初始化语 ...

  8. 解决winscp中普通用户无法上传、删除、移动文件

    上一篇博客中提到了winscp这个软件,这个软件可以利用sftp协议对linux服务器就行连接,然后方便我们对文件进行操作,但是如果是利用普通用户进行登陆的话,在对文件进行相关操作的时候会出现一些pe ...

  9. thumbs.db是什么文件

    thumbs.db是什么文件  这是图片缓存文件 Thumbs.db文件是一个数据库,里面保存了这个目录下所有图像文件的缩略图(格式为jpeg) thumbs.db删除不掉 反射获取某个类的 所有字段 ...

  10. 潭州课堂25班:Ph201805201 爬虫基础 第九课 图像处理- PIL (课堂笔记)

    Python图像处理-Pillow 简介 Python传统的图像处理库PIL(Python Imaging Library ),可以说基本上是Python处理图像的标准库,功能强大,使用简单. 但是由 ...