This chapter content

  1. The implementation of fast and slow forwarding of messages

  2. What’s their process, disassembling CoreFoundation

This ZhangMu

The contents of this chapter are not so important as to be understood, but what you need to remember is how to forward messages quickly or slowly. But their process, disassembler CoreFoundation can understand can be

The forwarding of messages

When the message is found in the fast and slow search process, dynamic protocols are found, it will enter the fast forwarding process of the message, if the fast forwarding is not implemented, it is necessary to see the slow forwarding process, if the IMP is not found, it will report an error

Rapid forwarding of messages

Can be used to prevent errors such as methods not found. Slow forwarding occurs when a message is not implemented in fast forwarding

// Fast forwarding of instance methods, In class or classification implementation - (id) forwardingTargetForSelector: (SEL) aSelector {nsstrings * errCls = NSStringFromClass (self. Class); NSString *errSel = NSStringFromSelector(aSelector); NSLog(@"%@ class instance method %@ has a problem ", errCls, errSel); NSString *clsName =@"NoneClass"; Class cls = NSClassFromString(clsName); if (! cls) { Class superCls = NSObject.class; cls = objc_allocateClassPair(superCls, clsName.UTF8String, 0); objc_registerClassPair(cls); } Method m = class_getInstanceMethod(cls, aSelector); if (! m) { class_addMethod(cls, aSelector, (IMP)doNothing, "v@:@"); } // Return [CLS alloc]; }Copy the code

Slow forwarding of messages

Slow forwarding is similar to fast forwarding. It is mainly about the direction of the method and the code of the method. See the previous article for method coding. NSMethodSignature means the method’s signature, let’s just say it’s the method invocation, and it should be used in conjunction with NSInvocation, i.e., message invocation.

-(NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { NSString *errCls = NSStringFromClass(self.class); NSString *errSel = NSStringFromSelector(aSelector); NSLog(@"%@ class instance method %@ has a problem ", errCls, errSel); NSMethodSignature *signature = [NSMethodSignature signatureWithObjCTypes:"v@:"]; return signature; } -(void)forwardInvocation:(NSInvocation *)anInvocation { NSString *clsName =@"NoneClass"; Class cls = NSClassFromString(clsName); NSObject *inst = cls ? [cls alloc] : nil; if (! cls) { Class superCls = NSObject.class; cls = objc_allocateClassPair(superCls, clsName.UTF8String, 0); objc_registerClassPair(cls); inst = [cls alloc]; } if (! [inst respondsToSelector:anInvocation.selector]) { Method m = class_getInstanceMethod(cls, anInvocation.selector); if (! m) { class_addMethod(cls, anInvocation.selector, (IMP)doNothing, "@@:@"); } anInvocation.target = inst; } [anInvocation invoke]; }Copy the code

Message not found

This method can be handled as an exception collection and will not work even if you handle messages in this method. If imp is not found, this method will be used. It doesn’t do anything special, it doesn’t make much sense, right

- (void)doesNotRecognizeSelector:(SEL)aSelector
{
    
}
Copy the code

The disassembly CoreFoundation

The reason for disassembly is because we are exploring the implementation of fast and slow forwarding of messages, CoreFoundation is not fully open source, and if we print the stack we can see that the method calls are mostly in CoreFoundation. It can only be viewed through disassembly, using tools such as Hopper and IDA.

We are going to disassemble the lookup process

When we look at the trigger process for forwarding a message, that is, who calls it. It’s inevitable to go to the breakpoint and look at the call stack. As you can see directly, the two main methods are ___forwarding___ and __forwarding_prep_0___

Disassemble pseudocode

  1. You can see__forwarding_prep_0___Call the___forwarding___

2. Next, there are pure screenshots, you can have a look if you are interested. The following process also says why the dynamic protocol method is executed twice in the dynamic protocol

3. This method is called if fast or slow message forwarding is not implemented4. Follow the process according to 3 to see this method. This method is going to call the method, which is why the dynamic protocol is executed twice, right

supplement

extern void instrumentObjcMessageSends(BOOL flag); This can be used for log printing by setting YES and NO before and after the place that needs to be printed.

For example, an error is reported after compilation. Then open the directory after

The address is:/tmp/msgSendsThis is something we can also find in the objc source code.Result: We can see how this method works