This is the ninth day of my participation in the August More text Challenge. For details, see: August More Text Challenge

Method could not find the process analysis

If all the superclasses are searched and no method is found, imp will be set to forward_IMP. If you go further, imp will return forward_IMP.

You see that forward_IMP has an assignment at the beginning of the method.

Next look for _objc_msgForward_impcache and find __objc_msgForward.

Then search for __objc_msgForward and see TailCallFunctionPointer x17.

Search for TailCallFunctionPointer and find that it jumps $0, which is x17 __objc_forward_handler

Next, search for __objc_forward_handler.

If you do not find the corresponding implementation, then you have gone from assembly to C, search for objc_forward_handler,! Objc2 watch see _objc_forward_stret_handler assigned for objc_defaultForwardStretHandler, then see objc_defaultForwardStretHandler function, It will be found here that it will print formatted, that is, print out when the method is not found. (obj->getIsa()) (object_getClassName); (selselname) (selselname);

Such as

So if an error occurs, is there a way to handle it? Next, you enter the message processing process.

Object method dynamic method resolution

Run a nonexistent method and set a breakpoint.

It then enters after typing a breakpoint in lookUpImpOrForward.

When it’s running, output the CLS to confirm that the message recipient is correct, in this case LGPerson is correct.

When I output imp, I find it is empty, because there is no method so it is correct.

So we go down here, where behavior is a method parameter.

Search where the behavior came from and what the value is. Found in MethodTableLookUp and has the value 3.

Back to loopUpImpOrForward, click on what LOOKUP_RESOLVER is

Behavior ^= LOOKUP_RESOLVER; behavior ^= LOOKUP_RESOLVER; So behavior (3) ^= 2 is just 1. If (slowPath (behavior & LOOKUP_RESOLVER)); if (slowpath(behavior & LOOKUP_RESOLVER)); Next, enter the resolveMethod_locked method.

This is not a metaclass, so go to resolveInstanceMethod.

There is another trycache. Why? So trycache, in fact, is putting the method in the cache so that the next trycache doesn’t look up the cache. Look specifically below here to follow the process. So this gives you a chance, if you implement resolveInstanceMethod:, to have a fault-tolerant processing. You see that you’re sending a message to a method, so it’s a class method.

Let’s do that

So when we run it, we know that before we get an error, we’ve got the resolveInstanceMethod method, self is LGPerson, sel is Sayasuofg. And notice that resolveInstanceMethod is called twice.

So the fact that we can come to the resolveInstanceMethod method before the error, means that we can handle it inside the resolveInstanceMethod and avoid the error.

Try adding method in resolveInstanceMethod to avoid errors.

Let’s run it.

No error was reported and the testFunc method was successfully called. Does lookUpImpOrNilTryCache in resolveInstanceMethod return if the resolveInstanceMethod method is not implemented?

The answer is NO, because there is a default implementation in nSObjCT that returns NO. Since the system would be more unstable if a return error was reported during the resolveInstanceMethod process, the system implements this method for our benefit.

Class method dynamic method resolution

Add an unimplemented class method and run it.

When it runs, it’s going to go into the else,

The resolveClassMethod method is then called, much like the object method dynamic resolution. Since class methods exist in metaclasses, operations are performed on the metaclasses in case the metaclasses are not initialized. And then you can see here that resolved is done by calling resolveClassMethod, so it should be done in resolveClassMethod. So where should resolveClassMethod go? In this case, the message receiver is a metaclass, and the object methods of the metaclass are the class methods of the class, so they should be written inside the class.

So let’s write down the resolveClassMethod.

Let’s run it and here comes the discovery.

Then we do the method substitution. The class method is inside the metaclass so you get the Metaclass.

Run it and find that the replacement is successful.

ResolveInstanceMethod is called once under resolveClassMethod. Why? And here, because class methods not only exist as class methods, but also as metaclass object methods, there’s also going to be a chain of inheritance of objects, which will eventually end up in NSObject.

Since object methods and class methods end up in NSObject, can they both be handled in NSObject? Let’s try it.

When we run it, we find that the methods are all replaced, indicating that it is feasible.

So why do we have dynamic resolution like this.

  1. Method search is the process of finding IMP through SEL. When an IMP is not found through SEL, Apple gives a chance to correct it so as not to report an error.
  2. When the global method fails to find the IMP, we can listen. This way we can listen to our own methods, and we can record them so that we can change them and process them to avoid a crash, such as jumping to the front page.

This approach is called AOP. AOP is aspect oriented programming, which implements unified maintenance of program functions by means of precompilation and dynamic proxy during runtime. AOP is a continuation of OOP, a hot topic in software development, an important content in Spring framework, and a derivative paradigm of functional programming. Using AOP can isolate each part of the business logic, so that the coupling degree between each part of the business logic is reduced, the reusability of the program is improved, and the efficiency of development is improved.

Why tryCache twice

Follow the process lookUpImpOrNilTryCache

_lookUpImpTryCache

lookUpImpOrForward

Log_and_fill_cache, so here, CLS has inserted the IMP of Sayasuofg into the cache

So to lookUpImpOrForwardTryCache came in

Imp is not nil, it’s libobjc.a.dylib_objc_msgforward_impcache, it’s not doing slow lookup, it’s just going to done, Then return (libobjc.a.dylib_objc_msgforward_impcache)

InstrumentObjcMessageSends auxiliary

Can be added in the code instrumentObjcMessageSends view call what method. Add unimplemented code and run it.

Go to the hidden file TMP in Macintosh HD.

Find the file that starts with msgSends and open it. To view

Assembler instruction reference.