preface
In the last article on dynamic method resolution, we talked about how a slow lookup of messages that were not found would enter dynamic resolution. If the dynamic resolution without processing, by log found something new forwardingTargetForSelector and methodSignatureForSelector, also is the last message lookup process forward.
forward
- Message forwarding is divided into
Fast forward
andSlowly forward
, let’s start with quick retweets.
Fast forward
Fast forward forwardingTargetForSelector, what role does this approach, the first to search in objc 818.2 source code, only talk about the way, did not find the specific use. To find the methods document Organizer – > CMD + shift + 0, then search forwardingTargetForSelector
forwardingTargetForSelector
- If the method doesn’t work, give it to someone else
Code validation
- The following in
Out of the source environment
To verify the
// .h
@interface WSPerson : NSObject
- (void)sayLike;
@end
// .m
@implementation WSPerson
- (id)forwardingTargetForSelector:(SEL)aSelector {
NSLog(- % @ @ "🎈 🎈 🎈 % s", __func__, NSStringFromSelector(aSelector));
return [super forwardingTargetForSelector:aSelector];
}
/ / call
WSPerson *person = [[WSPerson alloc] init];
[person sayLike];
@end
Copy the code
-
The execution result is as follows:
-
Will go here, can’t find the method is illustrated in the document, said method can’t find, you can specify a to perform, we add a in WSTeacher sayLike method, and implement, then forwardingTargetForSelector return values, designated as WSTeacher objects:
// WSTeacher.h
@interface WSTeacher : NSObject
- (void)sayLike;
@end
// WSTeacher.m
@implementation WSTeacher
- (void)sayLike {
NSLog("@" 🎉 🎉 🎉 % s, __func__);
}
@end
// WSPerson.m
@implementation WSPerson
- (id)forwardingTargetForSelector:(SEL)aSelector {
NSLog(- % @ @ "🎈 🎈 🎈 % s", __func__, NSStringFromSelector(aSelector));
return [WSTeacher alloc];
}
@end
Copy the code
The running results are as follows:
- Thus in
WSTeacher
Class, but there’s a downside to this process,If the specified class also does not implement the method
How to break? And then we go fromFast forwarding Changes to slow forwarding
.
Slowly forward
In auxiliary log msgSends, we can see that when forwardingTargetForSelector followed a methodSignatureForSelector method, namely fast forwarding didn’t find, Will enter methodSignatureForSelector method
methodSignatureForSelector
- Let’s look at
methodSignatureForSelector
Description:
- The document says that this method returns a method signature
NSMethodSignature
And must be created during the forwarding of the messageNSInvocation
, which is the realizationforwardInvocation
methods
Code validation
- To verify that the code can come in, first remove it
WSTeacher
In thesayLike
Implementation:
@implementation WSPerson
// Fast forward
- (id)forwardingTargetForSelector:(SEL)aSelector {
NSLog(- % @ @ "🎈 🎈 🎈 % s", __func__, NSStringFromSelector(aSelector));
return [WSTeacher alloc];
}
// Slow forwarding
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
NSLog(- % @ @ "🍊 🍊 🍊 % s", __func__, NSStringFromSelector(aSelector));
return [super methodSignatureForSelector:aSelector];
}
@end
Copy the code
- Let’s run it again
Question: methodSignatureForSelector incredibly didn’t go, is this why?
- Let’s take a look at this code and find out
forwardingTargetForSelector
Specifies theWSTeacher
To perform a search, butWSTeacher
It’s not implemented in the, so it’s not going to go, you can get rid of itFast forward
Try again:
The code comes in as expected, and it says in the document, it needs to go backThe method signature
And the implementationforwardInvocation
Method, we modify this code:
// Slow forwarding
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
NSLog(- % @ @ "🍊 🍊 🍊 % s", __func__, NSStringFromSelector(aSelector));
if (aSelector == @selector(sayLike)) {
return [NSMethodSignature signatureWithObjCTypes:"v@:"];
}
return [super methodSignatureForSelector:aSelector];
}
- (void)forwardInvocation:(NSInvocation *)anInvocation {
NSLog(@ % @ - % @ "", anInvocation.target, NSStringFromSelector(anInvocation.selector));
}
Copy the code
The running results are as follows:
So youYou avoid a crash
.forwardInvocation
Saves the method signature information inNSInvocation
You can also handle related transactions, such asSpecify the implementation
:
- (void)forwardInvocation:(NSInvocation *)anInvocation {
NSLog(@ % @ - % @ "", anInvocation.target, NSStringFromSelector(anInvocation.selector));
WSTeacher *t = [WSTeacher alloc];
if ([self respondsToSelector:anInvocation.selector]) {
[anInvocation invoke];
} else if ([t respondsToSelector:anInvocation.selector]) {
[anInvocation invokeWithTarget:t];
} else {
anInvocation.target = t;
anInvocation.selector = @selector(sayLearn);
[anInvocation invoke];
NSLog(@" The method cannot be found"); }}Copy the code
forwardInvocation
canSpecify to a class to call
, it can also beChange your target, change your selector
Etc.forwardInvocation
The process is essentially telling the programsayLike
If this method is still in place, the program will not do exception handling, but it does exist and can do it autonomously. However, this series of processes down, will cause a waste of resources.
conclusion
- Quick forward: call
forwardingTargetForSelector
To implement the fast forward process, you can return the object you want to implement for yourself to implement the method, ifReturns nil
Will enter theSlowly forward
Process. - Slow forwarding: Slow forwarding needs to be invoked
methodSignatureForSelector
andforwardInvocation
Achieve together,methodSignatureForSelector
You need to return the method signature, andforwardInvocation
It can do some processing, such as specifying object processing, specifying methods and so on. If there is no method signature, the slow search ends.
Message forwarding diagram
Look at the stack
- If these forwarding processes are not processed, the operation must be an error, so how to view, we can use
The bt command
Print stack:
The analysis shows that indoesNotRecognizeSelector
And then there are two ways to do it___forwarding___
and__forwarding_prep_0___
Methods, both of these methods are thereCoreFoundation
Library, in accordance with past experience to source analysis under the role, but in the sourceI didn't find it
,CoreFoundation
The library is not fully open source, so what? We can look at the dynamic library.
- Through the first
image list
Command to find the dynamic library path, and then findCoreFoundation
The dynamic library
- Then use the
Hopper
orIDA
To analyze, this article mainly inHopper
In the analysis
The disassembly (Hopper)
Analysis of the
Drag the found CoreFoundation dynamic library into the Hopper
- And then click on the left
label
search__forwarding_prep_0___
, mainly checkPseudo code
- We see
__forwarding_prep_0___
In the call___forwarding___
After getrax
, double-click to enter___forwarding___
Methods:
- Here is the judgment
forwardingTargetForSelector
There is no implementation, if not implementation will goloc_64ad7
, or slow forwarding:
- In slow forwarding, check whether the object is a zombie
_NSZombie_
, and then judgemethodSignatureForSelector
Whether to achieve, did not achieve to goloc_64e47
- if
methodSignatureForSelector
The return value isnil
, then goloc_64eac
Error - if
methodSignatureForSelector
If there is a return value, it will determineforwardStackInvocation
Method, and then do the rest of the processing
conclusion
hopper
You can also look at the process, but the process is not so comfortable and you have to analyze it slowly, you have to analyze it slowly, and you can still analyze and process the forwarding process.