This article is part of a review of Effective Objective-C 2.0, with a demo explaining the message forwarding mechanism in OC





Unrecognized selector sent to instance ** Because we called a method that doesn’t exist. In the OC message mechanism, the receiver of the message does not need to go to the corresponding selector, which starts the message forwarding mechanism. We can use code to tell the object how to handle the unknown message during the message forwarding process. The default implementation is to throw the following exception





unrecognized selector.png


Here’s an example of what happens before the exception is thrown:


The first step: After receiving an undecipherable message, the object calls +(BOOL)resolveInstanceMethod:(SEL) SEL or +(BOOL) resolveClassMethod:(SEL) SEL to ask whether a dynamic method is added to process the message

//People.m
void speak(id self, SEL _cmd){
    NSLog(@"Now I can speak.");
}
+ (BOOL)resolveInstanceMethod:(SEL)sel {
    
    NSLog(@"resolveInstanceMethod:  %@", NSStringFromSelector(sel));
    if (sel == @selector(speak)) {
        class_addMethod([self class], sel, (IMP)speak, "V@:");
        return YES;
    }
    return [super resolveInstanceMethod:sel];
}
Copy the code

When People receives a message from an unknown speak selector, instance methods will first call resolveInstanceMethod:. Method by judging the selectors and then dynamically adding a speak implementation method through class_addMethod method to solve the unknown message, at this time, the message forwarding process ends in advance. However, when People receive the unknown message fly, the first step returns No, that is, the second step will be called when there is No dynamically added implementation method


The second step: Since the first step has been asked and no new method has been added, ask if there is someone else who can help deal with it. Call is – (id) forwardingTargetForSelector: (SEL) aSelector the methods above, we said to the People received an unknown message selector to fly, ResolveInstanceMethod: fly, resolveInstanceMethod: fly, resolveInstanceMethod: fly, resolveInstanceMethod: fly, resolveInstanceMethod The code is as follows:

- (id)forwardingTargetForSelector:(SEL)aSelector {
    NSLog(@"forwardingTargetForSelector:  %@", NSStringFromSelector(aSelector));
    Bird *bird = [[Bird alloc] init];
    if ([bird respondsToSelector: aSelector]) {
        return bird;
    }
    return [super forwardingTargetForSelector: aSelector];
}
// Bird.m
- (void)fly {
    NSLog(@"I am a bird, I can fly.");
}
Copy the code

Through – (id) forwardingTargetForSelector aSelector: (SEL), the processing of bird to be able to deal with this message, so this message is processed by a bird success, message forwarding process end ahead of time. Console printing

forwardingTargetForSelector:  fly
I am a bird, I can fly.
Copy the code

But if – (id) forwardingTargetForSelector aSelector: (SEL) also can not find can help to deal with the unknown message, it will go to the last step, this step is one of the biggest step of price


Step 3: Call – (void)forwardInvocation:(NSInvocation *)anInvocation, Before calling forwardInvocation: calls – (NSMethodSignature *) methodSignatureForSelector: (SEL) aSelector method to get the selector method signature, Then in the -(void)forwardInvocation (NSInvocation *)anInvocation method you can use the anInvocation to get the corresponding message. Example code is as follows

When People receives a message with an option of CODE, they cannot process the first two steps and proceed to the third step:

- (void)forwardInvocation:(NSInvocation *)anInvocation {
    NSLog(@"forwardInvocation: %@", NSStringFromSelector([anInvocation selector]));
    if ([anInvocation selector] == @selector(code)) {
        Monkey *monkey = [[Monkey alloc] init];
        [anInvocation invokeWithTarget:monkey];
    }   
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    NSLog(@"method signature for selector: %@", NSStringFromSelector(aSelector));
    if (aSelector == @selector(code)) {
        return [NSMethodSignature signatureWithObjCTypes:"V@:@"];
    }
    return [super methodSignatureForSelector:aSelector];
}
Copy the code

The console will print

resolveInstanceMethod:  code
forwardingTargetForSelector:  code
method signature for selector: code
forwardInvocation: code
I am a coder.
Copy the code

At this point, the code message has been processed by the Monkey instance and the message forwarding process is complete. The complete message forwarding process is as follows:






So finally failed to deal with, is called the – (void) doesNotRecognizeSelector aSelector: (SEL) this method, we can also make some of text in this method, avoiding crash, but the only advice for processing in the online environment, Exceptions are thrown out during actual development

EOF: Message forwarding process in OC is basically like this, Demo point here, if you think it is helpful, don’t spare your star, due to my limited ability, there are inevitably some mistakes in the article, I hope you don’t hesitate to comment. + (BOOL)resolveClassMethod:(SEL) SEL how to dynamically add class methods to this method? For example, IF I send an unknown [People missMethod] message, how do I add +(void)missMethod implementation?