处理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. 【APUE | 10】函数signal

    函数signal 函数signal介绍 typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t ...

  2. zjoi 网络

    题解: 很显然会发现对于每种颜色分开处理这是一颗树 然后就是裸的lct 有个坑就是判断操作1 可能颜色改成跟原先一样的 代码: #include <bits/stdc++.h> using ...

  3. 8.Django-form组件

    1.form组件的校验功能 文件formsdemo models from django.db import models # Create your models here. class UserI ...

  4. 076 Apache的HBase与cdh的sqoop集成(不建议不同版本之间的集成)

    1.修改sqoop的配资文件 2.从mysql导入到hbase(import) bin/sqoop import \ --connect jdbc:mysql://linux-hadoop3.ibei ...

  5. TextInputLayout输入框验证

    <!-- 通过修改<color name="colorAccent">#023cfa</color>可以修改正确提示文本的颜色 添加<item ...

  6. 002.AnyCast技术浅析

    一      常见通信方式 1.1  UniCastAnyCast UniCast,即单播,指网络中一个节点与另一个节点之间需要建立一个单独的数据通道,从一个节点发出的信息只被一个节点收到,这种传送方 ...

  7. Android 7.0 PopupWindow 又引入新的问题,Google工程师也不够仔细么

    Android7.0 PopupWindow的兼容问题   Android7.0 中对 PopupWindow 这个常用的控件又做了一些改动,修复了以前遗留的一些问题的同时貌似又引入了一些问题,本文通 ...

  8. C# 创建多级文件夹示例

    string str = ""; ; i < j; i++) { str = str + "\\新建文件夹" ; } System.IO.Director ...

  9. Javascript中call,apply,bind的区别

    一.探索call方法原理 Function.prototype.call = function(obj) { // 1.让fn中的this指向obj // eval(this.toString().r ...

  10. bzoj2830: [Shoi2012]随机树

    题目链接 bzoj2830: [Shoi2012]随机树 题解 q1好做 设f[n]为扩展n次后的平均深度 那么\(f[n] = \frac{f[n - 1] * (n - 1) + f[n - 1] ...