-
Using runtime to dynamically add methods to prevent
Unrecognized Selector
errors prevents the app from crashing due to missing object and class methods.Instance method:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[TestClass losted:instance:method:]: unrecognized selector sent to instance 0x102c....'
Class method:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '+[TestClass losted:class:method:]: unrecognized selector sent to class 0x10000....'
-
Can get the specific information of the missing method, including:
- The class name of the missing class method or object method;
- The name of the missing method;
- The missing object method or class method.
The source file contains two module directories: TPUSELNormalForwarding
and TPUSELFastForwarding
; Drag all the files inside the Sources
folder in the corresponding module directory into you project.
TPUSELNormalForwarding
because some methods of the system use fast forwarding
CocoaPods
is a dependency manager for Cocoa projects. You can install it with the following command:
$ gem install cocoapods
To integrate TPreventUnrecognizedSEL
into your Xcode project using CocoaPods, specify it in your Podfile
:
# (pod 'TPreventUnrecognizedSEL') default is use (pod 'TPreventUnrecognizedSEL/NormalForwarding')
pod 'TPreventUnrecognizedSEL/NormalForwarding'
or this:
pod 'TPreventUnrecognizedSEL/FastForwarding'
Then, run the following command:
$ pod install
NormalForwarding
or FastForwarding
pod 'TPreventUnrecognizedSEL'
default is pod 'TPreventUnrecognizedSEL/NormalForwarding'
Carthage
is a decentralized dependency manager that builds your dependencies and provides you with binary frameworks.
You can install Carthage with Homebrew
using the following command:
$ brew update
$ brew install carthage
To integrate TPreventUnrecognizedSEL
into your Xcode project using Carthage, specify it in your Cartfile
:
github "tobedefined/TPreventUnrecognizedSEL"
Run carthage update
to build the framework and drag the built TPUSELNormalForwarding.framework
or TPUSELFastForwarding.framework
into your Xcode project.
TPUSELNormalForwarding.framework
or TPUSELFastForwarding.framework
.
After the project is imported, simply set which Classes to forward.
Module and lang \ Import module mode | Source File | 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 |
In the main()
function of the APP's main.m
file or in the APP's didFinishLaunching
method add the following code to get the specific information about the missing method:
// Setting does not process NSNull and its subclasses, the default is NO
[NSObject setIgnoreForwardNSNullClass:YES];
// Set the class and its subclasses in the array to not be processed (the class name in the array can be a Class type or an NSString type). By default, no class is ignored.
[NSObject setIgnoreForwardClassArray:@[@"SomeIgnoreClass1", [SomeIgnoreClass2 Class]]];
// Set to process only the classes in the array and their subclasses (the class name in the array can be either a Class or an NSString type). By default, all classes are handled.
[NSObject setJustForwardClassArray:@[@"SomeClass1", [SomeClass2 Class]]];
// Set callback after processing
[NSObject setHandleUnrecognizedSELErrorBlock:^(Class _Nonnull __unsafe_unretained cls, SEL _Nonnull selector, UnrecognizedMethodType methodType, NSArray<NSString *> * _Nonnull callStackSymbols) {
// DO SOMETHING
// like upload to server or print log or others
}];
// Set to process only the classes in the array and their subclasses (the class name in the array can be either a Class or an NSString type). By default, all classes are NOT handled.
// Set callback after processing
[NSObject setJustForwardClassArray:@[@"SomeClass1", [SomeClass2 Class]]
handleUnrecognizedSELErrorBlock:^(Class _Nonnull __unsafe_unretained cls, SEL _Nonnull selector, UnrecognizedMethodType methodType, NSArray<NSString *> * _Nonnull callStackSymbols) {
// DO SOMETHING
// like upload to server or print log or others
}];
The following definitions and methods are in NSObject+TPUSELFastForwarding.h
or 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
type; the Class of missing instance method or class method,NSStringFromClass(cls)
can be used to return the NSString for the class nameselector
:SEL
type; the missing method name,NSStringFromSelector(selector)
can be used to return the NSString for the method namemethodType
:UnrecognizedMethodType
type; for the missing method type (class method or object method)callStackSymbols
:NSArray<NSString *> *
type; call stack infomations