-
使用runtime动态添加方法防止产生
Unrecognized Selector
错误,可以防止因为对象方法和类方法缺失所产生的APP崩溃。对象方法:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[TestClass losted:instance:method:]: unrecognized selector sent to instance 0x102c....'
类方法:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[TestClass losted:class:method:]: unrecognized selector sent to class 0x10000....'
-
可以获取缺失方法的具体信息,包括:
- 缺失类方法或对象方法的类名;
- 所缺失的方法名;
- 缺失的是对象方法还是类方法。
源文件中包含两个模块目录: TPUSELNormalForwarding
和 TPUSELFastForwarding
;将对应模块目录中的Sources
文件夹内部的所有文件拖入项目中即可
TPUSELNormalForwarding
,因为系统的某些方法使用了快速转发FastForwarding技术
CocoaPods
是一个Cocoa项目管理器。你可以使用以下命令去安装CocoaPods
:
$ gem install cocoapods
要使用CocoaPods将TPreventUnrecognizedSEL
集成到您的Xcode项目中,请在Podfile
中加入:
# pod 'TPreventUnrecognizedSEL' 默认是使用 pod 'TPreventUnrecognizedSEL/NormalForwarding'
pod 'TPreventUnrecognizedSEL/NormalForwarding'
或者加入
pod 'TPreventUnrecognizedSEL/FastForwarding'
然后运行一下命令:
$ pod install
NormalForwarding
和 FastForwarding
二者只能选其一
pod 'TPreventUnrecognizedSEL'
默认是pod 'TPreventUnrecognizedSEL/NormalForwarding'
Carthage
是一个去中心化的依赖管理器,它构建并提供所使用的库的framework。
你可以使用 Homebrew
并运行下面的命令安装Carthage
$ brew update
$ brew install carthage
要将TPreventUnrecognizedSEL
集成到使用Carthage的Xcode项目中,请在Cartfile
中加入:
github "tobedefined/TPreventUnrecognizedSEL"
运行carthage update
构建framework,并将编译的对应平台的TPUSELNormalForwarding.framework
或者TPUSELFastForwarding.framework
拖入Xcode项目中。
TPUSELNormalForwarding.framework
和 TPUSELFastForwarding.framework
二者选一
导入项目之后简单设置对哪些Class进行forwarding即可。
模块和语言 \ 导入模块方式 | 源文件 | CocoaPods | Carthage |
---|---|---|---|
TPUSELNormalForwarding & ObjC | #import "TPUSELNormalForwarding.h" | #import <TPreventUnrecognizedSEL/TPUSELNormalForwarding.h> | #import <TPUSELNormalForwarding/TPUSELNormalForwarding.h> |
TPUSELNormalForwarding & Swift | add ⤴ in Bridging-Header | import TPreventUnrecognizedSEL | import TPUSELNormalForwarding |
TPUSELFastForwarding & ObjC | #import "TPUSELFastForwarding.h" | #import <TPreventUnrecognizedSEL/TPUSELFastForwarding.h> | #import <TPUSELFastForwarding/TPUSELFastForwarding.h> |
TPUSELFastForwarding & Swift | add ⤴ in Bridging-Header | import TPreventUnrecognizedSEL | import TPUSELFastForwarding |
在APP的 main.m
文件的main()
函数中 或者 在APP的didFinishLaunching
方法中 加入以下代码可以获得缺失方法的具体信息:
// 设置不对NSNull及其子类进行处理,默认为NO
[NSObject setIgnoreForwardNSNullClass:YES];
// 设置不对数组中的类及其子类进行处理(数组中的类名可以为Class类型也可以为NSString类型),默认不忽略任何类
[NSObject setIgnoreForwardClassArray:@[@"SomeIgnoreClass1", [SomeIgnoreClass2 Class]]];
// 设置仅处理数组中的类及其子类(数组中的类名可以为Class类型也可以为NSString类型),默认处理所有类
[NSObject setJustForwardClassArray:@[@"SomeClass1", [SomeClass2 Class]]];
// 设置处理之后的回调操作
[NSObject setHandleUnrecognizedSELErrorBlock:^(Class _Nonnull __unsafe_unretained cls, SEL _Nonnull selector, UnrecognizedMethodType methodType, NSArray<NSString *> * _Nonnull callStackSymbols) {
// 在这里写你要做的事情
// 比如上传到服务器或者打印log等
}];
// 设置仅处理数组中的类及其子类(数组中的类名可以为Class类型也可以为NSString类型),默认不处理任何类
// 设置处理之后的回调操作
[NSObject setJustForwardClassArray:@[@"SomeClass1", [SomeClass2 Class]]
handleUnrecognizedSELErrorBlock:^(Class _Nonnull __unsafe_unretained cls, SEL _Nonnull selector, UnrecognizedMethodType methodType, NSArray<NSString *> * _Nonnull callStackSymbols) {
// 在这里写你要做的事情
// 比如上传到服务器或者打印log等
}];
在NSObject+TPUSELFastForwarding.h
或者NSObject+TPUSELNormalForwarding.h
中有以下定义和方法
typedef NS_ENUM(NSUInteger, UnrecognizedMethodType) {
UnrecognizedMethodTypeClassMethod = 1,
UnrecognizedMethodTypeInstanceMethod = 2,
};
typedef void (^ __nullable HandleUnrecognizedSELErrorBlock)(Class cls,
SEL selector,
UnrecognizedMethodType methodType,
NSArray<NSString *> *callStackSymbols);
cls
:Class
类型;为缺失方法的类或对象的Class,可使用NSStringFromClass(cls)
返回类名字符串selector
:SEL
类型;为所缺失的方法名,可使用NSStringFromSelector(selector)
返回方法名的字符串methodType
:UnrecognizedMethodType
类型;为所缺失的方法类型(类方法or对象方法)callStackSymbols
:NSArray<NSString *> *
类型;为调用栈信息