iOS – message forwarding mechanism
I believe you are familiar with this sentence unrecognized selector sent to instance 0x ******************************************************************.
Let's briefly talk about saving the code about to crash - iOS message forwarding
Dynamic binding
Because OC is a dynamic runtime language, one of its features is dynamic binding.
Regarding dynamic binding, the explanation given on Apple's official website is: (determining the method to invoke at runtime).
To put it simply: the program can't determine the actual method to call until it executes.
This creates a problem. I can send a message to an instance to execute a method that does not belong to me. unrecognized selector sent to instance will appear at this time.
If this happens, we can apply message forwarding to solve this problem. Turn this method that does not belong to you into your own method, or find an instance with this method to execute this method.
Save code that is about to crash
Step 1: Method Analysis and processing stage | dynamic method resolution
Within this method, you can dynamically add methods for the current class.
Point the method implementation of sel to an existing method
/** Method analysis processing stage | dynamic method resolution Within this method, you can dynamically add methods for the current class. Point the method implementation of sel to an existing method */ + (BOOL)resolveInstanceMethod:(SEL)sel { NSString *selectorString = NSStringFromSelector(sel); printf("%s %s\n", __func__, selectorString.UTF8String); // Get the instance method of class according to sel Method method = class_getInstanceMethod([self class], @selector(dynamic_method)); // Get the function pointer of class according to sel IMP method_imp = class_getMethodImplementation([self class], @selector(dynamic_method)); // Add an implementation to sel that cannot be found BOOL ret = class_addMethod([self class], sel, method_imp, method_getTypeEncoding(method)); printf("%s\n", ret?"Exchange added successfully":"Exchange add failed"); // The returned result does not affect the process return YES; }
Step 2 fast forwarding stage | fast search
Triggered when the problem is not solved in the previous step.
Return an instance that can respond to aSelector, that is, forward aSelector to another class.
/** Fast forwarding stage | fast search Triggered when the problem is not solved in the previous step. Return an instance that can respond to aSelector, that is, forward aSelector to another class. */ - (id)forwardingTargetForSelector:(SEL)aSelector { NSString *selectorString = NSStringFromSelector(aSelector); printf("%s %s\n", __func__, selectorString.UTF8String); if ([selectorString isEqualToString:@"no_imp_method"]) { // Returns an instance that implements the aSelector function // If the instance does not implement aSelector, go to the next step, methodSignatureForSelector printf("%s Forward message to BackUpClass\n",__func__); return [[BackUpClass alloc] init]; } // If self or nil is returned, it indicates that there is no target that can respond. Then go to the next step, methodSignatureForSelector. return nil; }
Step 3: normal forwarding stage | slow lookup
Get a method signature. The signature is generated by an instance that responds to aSelector.
If there is a signature, the last step of message forwarding is forwardInvocation.
/** General forwarding phase | slow lookup Returns a method signature. The signature is generated by an instance that responds to aSelector. */ - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { NSString *selectorString = NSStringFromSelector(aSelector); printf("%s %s\n", __func__, selectorString.UTF8String); BackUpClass * backUp = [BackUpClass new]; NSMethodSignature * sign = [backUp methodSignatureForSelector:aSelector]; //If there is a signature, the last step of message forwarding is forwardInvocation return sign; }
You can also do nothing. So far, the message forwarding is over and there will be no crash.
/** Forward sel to an object that actually implements sel You can also do nothing. So far, the message forwarding is over and there will be no crash. */ - (void)forwardInvocation:(NSInvocation *)anInvocation { printf("%s %s\n",__func__ , anInvocation.description.UTF8String); // Create alternate message receiving object BackUpClass * backUp = [[BackUpClass alloc] init]; printf("%s Forward message to BackUpClass\n",__func__); [anInvocation invokeWithTarget:backUp]; }
Write it at the back
Talk about. Can communicate.