1. Review
The dynamic method parsing phase was analyzed in the previous post, Runtime 4: Dynamic Method Parsing. This post focuses on the third phase of message sending — > message forwarding.
Dynamic method parsing, if not processed, will enter the message sending process, so what methods will be called by the message forwarding process?
Between now and then, in apple’s source found a magic methods instrumentObjcMessageSends inside, this is a way to print the log.
void instrumentObjcMessageSends(BOOL flag)
{
bool enable = flag;
// Shortcut NOP
if (objcMsgLogEnabled == enable)
return;
// If enabling, flush all method caches so we get some traces
if (enable)
_objc_flush_caches(Nil);
// Sync our log file
if(objcMsgLogFD ! =- 1)
fsync (objcMsgLogFD);
objcMsgLogEnabled = enable;
}
Copy the code
So let’s write 🌰 to see what methods are called for message forwarding.
extern void instrumentObjcMessageSends(BOOL flag);
int main(int argc, const char * argv[]) {
@autoreleasepool {
instrumentObjcMessageSends(YES);
LGPerson *person = [LGPerson alloc];
[person sayInstanceMethod];
instrumentObjcMessageSends(NO);
NSLog(@"Hello, World!");
}
return 0;
}
Copy the code
Go to Mac Access -> Go -> enter/TMP /msgSends to open the file directory
Double-click to open the generated msgSends-5425 log file
From the log file can be found that the dynamic method invocation resolveInstanceMethod: method is called after forwardingTargetForSelector, methodSignatureForSelector: , resolveInstanceMethod: and doesNotRecognizeSelector: method. So let’s explore each of them.
2. Fast forwarding
From Xcode documentation can search to forwardingTargetForSelector method of definition, and usage.
- ForwardingTargetForSelector definition
Returns an object to which an unrecognized message is directed. To put it bluntly, look for a recipient, can also be understood as “take the blame”, haha!
- (id)forwardingTargetForSelector:(SEL)aSelector{
NSLog(@"%s - %@",__func__,NSStringFromSelector(aSelector));
return [JPStudent alloc];
}
Copy the code
- ForwardingTargetForSelector code implementation
Calling [person sayHello] is a sure way to break when the JPPerson class doesn’t implement the sayHello method, but let’s leave it to the sayHello guy.
If the runtime does not find the implementation of the invoked method in the first step of message forwarding, the current receiver has a second chance to process. At this moment the run-time system calls – (id) forwardingTargetForSelector (SEL) aSelector method, this method can return a can deal with the object, the runtime system will find, according to the object returned if find the jump to the corresponding method of implementation, message forwarding.
3. Slow forwarding
If there is no blame for fast forwarding, the programmer will not deal with it and enter the slow forwarding process.
3.1 Method Signature
- MethodSignatureForSelector definition
Returns an NSMethodSignature object that contains the description of the method identified by the given selector. Is simply the method signature, methodSignatureForSelector must be used together with forwardInvocation
//// Slow forwarding
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
NSLog(@"%s - %@",__func__,NSStringFromSelector(aSelector));
if (aSelector == @selector(sayHello)) {
return [NSMethodSignature signatureWithObjCTypes:"v@:@"];
}
return [super methodSignatureForSelector:aSelector];
}
Copy the code
3.2 Message Forwarding
- ForwardInvocation definition
The above method signature information is stored in the NSInvocation, and the method number is obtained from SEL SEL = [anInvocation selector]
- (void)forwardInvocation:(NSInvocation *)anInvocation{
// NSLog(@"%@ - %@",anInvocation.target,NSStringFromSelector(anInvocation.selector));
JPStudent *s = [JPStudent alloc];
if ([self respondsToSelector:anInvocation.selector]) {
[anInvocation invoke];
}else if ([s respondsToSelector:anInvocation.selector]){
[anInvocation invokeWithTarget:s];
}else{
NSLog(@"%s - %@",__func__,NSStringFromSelector(anInvocation.selector)); }}Copy the code
4. The message is not processed
If the above methods are not implemented, can perform – (void) doesNotRecognizeSelector aSelector: (SEL) this method
Apple: I designed so clever, give you programmer so many times remedial opportunity, you unexpectedly do not deal with, ah! Well, I can’t crash the program!
// If none of the above processes is processed and no message handlers are found, this is executed- (void)doesNotRecognizeSelector:(SEL)aSelector {
NSLog(@" Can't find a way");
}
Copy the code
5. To summarize
-
The dynamic method parsing is not processed, and the message forwarding process is entered
-
The message forwarding process includes fast forwarding and slow forwarding
-
DoesNotRecognizeSelector can be implemented to prevent crashes if the message forwarding phase, fast forwarding and slow forwarding are not handled
-
Message forwarding Flowchart
More to come
🌹 just like it 👍🌹
🌹 feel learned, can come a wave, collect + concern, comment + forward, lest you can’t find me next 😁🌹
🌹 welcome everyone to leave a message to exchange, criticize and correct, learn from each other 😁, improve self 🌹