preface
Dynamic method resolution is explored in IOS underlying principles of dynamic method resolution. After the dynamic resolution through log auxiliary function to realize forwardingTargetForSelector and methodSignatureForSelector method, that is the message sent by the last process forward
The preparatory work
- Objc4-818.2 – the source code
- CF source
- Disassembly tool
Hopper
andida
forward
Message sending after the dynamic method resolution still did not find the real method implementation, at this time the dynamic method resolution throw IMP = forward_IMP into the message forwarding process. The forwarding process consists of two steps: fast forwarding and slow forwarding
Fast forward
forwardingTargetForSelector
Through the auxiliary function to realize forwardingTargetForSelector log, but specific means nothing, this method to recognize this method below. Open the Xcode, command + shift + 0, then the global search forwardingTargetForSelector
forwardingTargetForSelector
The meaning is to return an unrecognized messageredirect
Specify an object to receive the message
Examples explore fast forwarding
First define the LWPerson and LWTest classes, and then call the sayHello method in the main function. LWPerson does not implement sayHello method, LWTest class implements sayHello method, LWTest class and LWPerson class may not inherit relationship
@implementation LWPerson
-(id)forwardingTargetForSelector:(SEL)aSelector{
if (aSelector == @selector(sayHello)) {
return [[LWTest alloc] init];
}
return [super forwardingTargetForSelector:aSelector];
}
@end
Copy the code
@implementation LWTest
-(void)sayHello{
NSLog(@"---%s---",__func__);
}
@end
Copy the code
int main(int argc, char * argv[]) {
@autoreleasepool {
LWPerson * p = [LWPerson alloc];
[p sayHello];
}
return 0;
}
Copy the code
202107 -- 05 17:21:58.201416+0800 objc_msgSend[23131:807070] ----[LWTest sayHello]---
Copy the code
The printed result shows that LWTest class has no relationship with LWPerson class, but it can still be queried at last when it is assigned to LWTest class, and there is no crash message. In fact, the message is searched in the class closely related to LWTest first, but it is not found at last. So the system gives this permission to the developer, and you tell me which object and class can receive this message. The jar is broken, which I didn’t expect.
If you do not give the specified class implementation, fast forwarding is not possible, the system has no bottom line to give you slow forwarding, ridiculous
Slowly forward
Slow forward methodSignatureForSelector is also news to find the last process. Give dynamic method resolution, give fast forwarding, give you a chance to slow forwarding. They say it’s three things, it’s too much for the system to handle, and they’ll give you crash rattail juice
MethodSignatureForSelector means returns a NSMethodSignature object, the object contains by a given selector identifies the description of the method. MethodSignatureForSelector collocation and forwardInvocation use commonly, if methodSignatureForSelector method returns a nil forwardInvocation wouldn’t call
@implementation LWPerson
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation{
NSLog(@"% @ - - -",anInvocation);
}
@end
Copy the code
202107 -- 05 21:09:59.688392+0800 objc_msgSend[1121:21900] -[LWPerson sayHello]:
unrecognized selector sent to instance 0x60000001c000
Copy the code
MethodSignatureForSelector at this time of the return value is nil, slow forward completed, melt directly
@implementation LWPerson
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector{
if (aSelector == @selector(sayHello)) {
return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}
return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation{
NSLog(@"-- - % @ - % @",anInvocation.target,NSStringFromSelector(anInvocation.selector));
}
@end
Copy the code
202107 -- 05 21:42:47.001759+0800 objc_msgSend[1629:44959] ---<LWPerson: 0x60000000c140>---sayHello
Copy the code
If methodSignatureForSelector return values is NSMethodSignature object, will call forwardInvocation physical processing anInvocation saved NSMethodSignature signature information, There is also the method signature SEL for the target method, and the recipient of the method. The crash message is not reported at this time, of course, can also process anInvocaion transaction
- (void)forwardInvocation:(NSInvocation *)anInvocation{
LWTest * test = [LWTest alloc];
anInvocation.target = test;
anInvocation.selector = @selector(sayBeautiful);
[anInvocation invoke];
}
Copy the code
202107 -- 05 21:52:29.117134+0800 objc_msgSend[1787:51943] ----[LWTest sayBeautiful]---
Copy the code
The anInvocation target is [LWTest alloc], the anInvocation Selector is @Selector (sayBeautiful), and the [anInvocation invoke] invokes the message. The forwardInvocation is like a distribution center for unrecognized messages and can translate one message to another or simply “eat” some messages. So it doesn’t collapse without processing
Message exchange summary
- Fast forwarding: Pass
forwardingTargetForSelector
Implementation, if there is a specified object to receive the message, will go through the specified object search process, if the return isnil
To enter the slow forwarding process - Slow forwarding: Yes
methodSignatureForSelector
andforwardInvocation
Co-realization, ifmethodSignatureForSelector
The return value isnil
, slow search process ends if there is a return valueforwardInvocation
The transaction does not crash without being processed
Message Forwarding Flowchart
The disassembly
Method call crashes and stack information is displayed from__forwarding_prep_0___
It’s called again at the end of the calldoesNotRecognizeSelector
. Explore the specific process
__forwarding_prep_0___ is part of the CoreFoundation system library
After downloading the code of CoreFoundation library, there is no global search in the source code, indicating that this content is not provided by Apple
Hopper
orida
explore
Hopper disassembler, we disassembler CoreFoundation executable, to find __forwarding_prep_0___, CoreFoundation executable how to obtain
image list
You can obtain the list of all image filesCoreFoundation
File path to
Global search__forwarding_prep_0___
Is found only one, and will be called__forwarding__
And into the__forwarding__
methods
- if
forwardingTargetForSelector
Method not implemented, jumploc_64ad7
process - if
forwardingTargetForSelector
The return value of the method isnil
Jump,loc_64ad7
process
At this point, the slow forwarding process is entered
- if
methodSignatureForSelector
No direct jump toloc_64e47
process - if
methodSignatureForSelector
Return value is equal tonil
Jump toloc_64eac
process - if
methodSignatureForSelector
Object that returns signature information
loc_64e47
Flow: Directly report an error and jump toloc_64eac
processloc_64eac
Process:doesNotRecognizeSelector
Collapse treatment
Returns the forwardInvocation method with signature information to handle the transaction
conclusion
The exploration of the method is basically over. In my opinion, it is the most important to realize the whole thinking and way of the exploration through the exploration method