Message mechanism

An overview of the

In OC, methods are stored in the class as method name :sel + function pointer: IMP. The underlying implementation of method invocation is an objc_msgSend function. The method invocation is actually calling this function, so it is called message mechanism. When sending a message, the caller is the message receiver, and the body of the message is sel, which is the information about the method name and parameters.

The objc_msgSend function firstly finds the location of method storage along the inheritance chain according to the caller’s ISA information, and then finds the corresponding IMP in the method list according to sel, and then calls it. If the entire inheritance chain is not found, the system finally gives three chances to save the unimplemented method. If all three chances are not grasped, a classic error is reported, that is, the method cannot be found. So the whole method call process is mainly divided into two parts, one is to find IMP, the second is to save the scheme;

The difference between object methods and class methods: before the specific interpretation of the message mechanism is necessary again the difference between object methods and class methods, behind such explanations up more convenient, object method exists class list, class methods exist metaclass list, class can also be understood as a class object, the metaclass is system generated. So without special explanation, methods include object methods and class methods, and objects include class objects.

The message flow

If find IMP to call, nothing to say, so mainly said, if can not find, how to find the next step, where to find, how to deal with the end, such a process.

An IMP is first defined externally and assigned when it is found. And then you call it.

One. Send a message – findimp

1. Do a quick lookup

The imp function pointer will be found in the cache of the class. The imp function pointer will be found in the cache of the class’s method. This process is an in-memory operation, so it’s called a quick lookup. On the other hand, For efficiency purposes, Apple writes this code in collections, which are available in objC source files.

Imp is the address of a pointer to a function, which can also be understood as a function name.

If an IMP is found in the cache, call imp. If not, this method is called for the first time, and then enter the slow search process.

Methods inherited from the parent are stored in the parent’s cache and are found during slow lookups.

2. Slow search

When the method is not found in the cache, it goes to lookUpImpOrForward, which is written in C++ and jumps from assembly to C++.

Note: Before starting the slow lookup, a quick lookup is performed. This is due to the influence of multiple threads, which may be called by another thread during this interval and inserted into the cache.

To begin a formal slow search:

  1. In this classbitsTake out of structuremethod_list, according to theselTo find theimpThe other thing you need to do when you find it is to go from the current index to the first index, because the classification of this class may override the method, and the classification method is inmethod_listIs at the top of the list, which is why the classification method is of high priority.
  2. If it’s not found in this class, it goes down the inheritance chain toThe parent classthecacheLook for;
  3. If you’re in the parent classcacheIs not found, it will repeat the first two steps along the inheritance chain;

forward_imp : If the NSObject base class doesn’t find it all the way through, the imp temporary variable is assigned a system function pointer, forward_IMP, This function throws an error: Unregnizered Selector sent to instance XXX, and the system stops the program. The fact that the method cannot be found does not cause the program to crash, it can be said that the artificial stop, because this error has affected the correct execution of the program.

Note:

When you’re looking for a class method, you’re actually looking in the metaclass, and if you don’t find it in the root metaclass, because the parent of the root metaclass is NSObject, and the metaclass of NSObject is also the root metaclass, so you end up finding NSObject, and see if NSObject has any object methods with the same name, If there is an object method with the same name, and if it finds one, that object method is called.

So you have A situation where when you call A class method A, the whole inheritance chain doesn’t have that class method, and NSObject (including classes) has an object method A, it doesn’t crash, it gets called.

Sidebar: When looking up method_list in step 1, we use a binary lookup algorithm, and sel is sorted after transformation;

Ii. Rescue plan

If the IMP corresponding to SEL cannot be found in the whole inheritance chain, then the process of the rescue scheme will be entered. The system gives three chances to save, which can also be said to be a fault tolerance mechanism.

2.1 Method Resolution

After the temporary variable imp is assigned the value forward_IMP, the method resolution phase is entered. A +(BOOL)resolveInstanceMethod (SEL) SEL, a +(BOOL)resolveClassMethod (SEL) SEL The system will send a message to the current class, call the corresponding resolution method, and that message will be the same as above, and it will look up the inheritance chain all the way to the NSObject base class.

If the class’s inheritance chain implements the corresponding resolution method. You can do something in this method, for example, you can use runtime to bind sel to an IMP, and then return YES, so that the IMP will be called to the corresponding method, and not crash. For example, you can send SEL information, class name, method name and so on back to the server, return NO and let the program continue.

Note: When you do class method resolution, you’re actually looking down the metaclass inheritance chain, and if you go to the NSOject base class, and you haven’t found it yet, you do an object method resolution on NSOject, because the parent of the metaclass is Also NSOject, And finally I’m going to find out if NSOject implements (BOOL)resolveInstanceMethod:(SEL) SEL.

If you don’t find a way to decide. Will enter the following message forwarding continent, first into the fast forwarding, if there is no solution to enter the slow forwarding.

2.2 Fast Forwarding

Fast forward will call the current class or in the inheritance chain – (id) forwardingTargetForSelector aSelector: (SEL), returns a capable of handling the message object. This means that either the new object has an object with the same name as sel (class object), or the sel is bound to an IMP and returns self to continue processing the message. Anyway, this message can be processed. The program can continue to execute

2.3 Slow Forwarding

Slow forward will call – (NSMethodSignature *) methodSignatureForSelector: (SEL) aSelector required to return a method’s signature, The – (void)forwardInvocation (NSInvocation *)anInvocation method is then called and the transaction is thrown out. If both methods are implemented and the method signature returned is valid (correct), the application will not crash. When the system throws a transaction and the developer receives it, it’s already handled, so it doesn’t crash. It is up to the developer whether or not the transaction is processed;

The developer can modify the transaction’s message receiver, SEL, method signature, and then execute the transaction; Alternatively, you can save the transaction for the time being and execute it when appropriate.

Throw an error

If all three of the rescue opportunities are not grasped, then the final error will be thrown. It terminates the program by calling IMP, the system function forward_IMP assigned at the end of the slow search.

conclusion

This is the end of the main flow of the messaging mechanism. Of course, this process saves a lot of details, such as thread control, locking, judgment, assertion, message flow state and so on, interested can download objC source code to have a look, research.

If you want to understand the message mechanism more thoroughly, it is necessary to class structure and ISA bitmap these two knowledge. Please refer to several other articles;

The ISA pointer goes to the bits cache of the memory layout

  • Isa bitmap