iOS underlying development message mechanism (IV) message forwarding

Source: Internet
Author: User

Message Forwarding

In order for a class to understand a message, we must implement the corresponding method in code. However, at compile time, sending a message to the class that it cannot read does not give an error, because you can continue to add methods to the class at run time, so the compiler does not know in any way whether a method will be implemented in the class. When an object receives a message that cannot be interpreted, the message forwarding mechanism is started, and the programmer can tell the object how to handle the unknown message by this procedure.

You may have already encountered messages that were handled by the message forwarding process, just without notice. If you see the following information in the console, you have sent a message to an object that it cannot read, initiating the message forwarding mechanism and forwarding the message to the default implementation of NSObject.

 1 -[__nscfnumber lowercasestring]: Unrecognized selector sent to  2  instance   terminating app due to uncaught Exception  "  nsinvalidargumentexception  , Reason:   

The above exception message is thrown by NSObject's "Doesnotrecognizeselector:" method, which indicates that the type of the message receiver is _ _nscfnumber, The recipient cannot understand the selector named LowerCaseString. This is not surprising in this case, because there is no method named LowerCaseString in the NSNumber class. The one you see in the console is the inner class (internal class) used to implement "seamless bridging" (toll-free bridging, 49th, which will explain this technique), and this object is also created when the NSNumber object is configured. In this case, the message forwarding process ended up with an application crash, but when developers write their own classes, they can set hooks in the forwarding process to execute the predetermined logic without crashing the application.

Message forwarding is divided into two major phases. The first stage is to ask the receiver, the class to see if it can dynamically add methods to handle the current "unknown selector" (unknown selector), which is called "Dynamic Method Resolution" (resolution). The second phase involves a "complete message forwarding mechanism" (full forwarding mechanism). If the run-time system has finished executing the first phase, the receiver cannot respond to the message containing the selector by means of a dynamic new method. At this point, the runtime system requests the recipient to handle the message-related method calls in other ways. This is subdivided into two small steps. First, ask the recipient to see if there are any other objects that can handle this message. If so, the runtime system will transfer the message to that object, and the message forwarding process ends, as usual. Without the replacement receiver, a full message forwarding mechanism is initiated, and the runtime system encapsulates all the details related to the message into the Nsinvocation object, giving the receiver the last chance to To try to resolve the message that is not currently being processed

Dynamic Method Parsing

When an object receives a message that cannot be read, the following class methods of the class to which it belongs are called first:

The parameter of the method is the unknown selector, and its return value is Boolean, indicating whether the class can add an instance method to handle this selector. This class has the opportunity to add a new method to handle this selector before proceeding to the forwarding mechanism. If the method that has not been implemented is not an instance method but a class method, then the runtime system calls another method, similar to "Resolveinstancemethod:", which is called "Resolveclassmethod:".

The premise of using this approach is: the implementation of the relevant methods of code has been written, just waiting for the runtime to plug in the dynamic in the class. This scenario is often used to implement the @dynamic attribute (see 6th), for example, to access the properties of Nsmanagedobjects objects in the CoreData framework, as the access methods required to implement these properties are determined at compile time.

The following code demonstrates how to implement the @dynamic property with "Resolveinstancemethod:":

1 ID autodictionarygetter (id self, SEL _cmd); 2 voidAutodictionarysetter (id self, SEL _cmd, id value); 3  4+(BOOL) Resolveinstancemethod: (SEL) Selector {5NSString *selectorstring =Nsstringfromselector (selector); 6     if(/*selector is from a @dynamic property*/ ) {  7         if([selectorstring Hasprefix:@"Set"]) {  8 Class_addmethod (self,9 Selector,Ten (IMP) Autodictionarysetter, One                             "[Email protected]:@");  A}Else {   - Class_addmethod (self, - Selector, the (IMP) Autodictionarygetter, -                             "@@:");  -         }   -         returnYES;  +     }   - return[Super Resolveinstancemethod:selector];  +}

The selection is first converted to a string and then detected to indicate whether it represents a set method. If the prefix is set, the setting method is used, or the method is obtained. In either case, the method that handles the selector is added to the class, and the method that you add is implemented with a pure C function. The C function may use code to manipulate the associated data structure, and the attribute data in the class is stored in those data structures. In CoreData, for example, these access methods may have to communicate with the backend database in order to obtain or update the corresponding values.

Recipients of redundancy

The current recipient has a second chance to handle the unknown selector, and in this step the runtime system will ask: Can you pass this message to another recipient for processing? The process that corresponds to this step is as follows:

-(ID

The method parameter represents the unknown selector, and if the current recipient can find the redundancy object, return it, and nil if it cannot be found. With this scheme, we can use "combination" (composition) to simulate some of the characteristics of "multiple inheritance" (Multiple inheritance). Within an object, there may be a series of other objects that can be returned by this method to the related internal object that will be able to handle a selection, so that the object is seen as if it had handled the messages in person.

Please note that we are unable to manipulate the messages forwarded through this step. If you want to modify the message content before sending it to the recipient, it has to be done through the full message forwarding mechanism.

Full message forwarding

If the forwarding algorithm has come to this step, then the only thing that can be done is to enable the full message forwarding mechanism. The Nsinvocation object is created first, and all the details related to the message that has not been processed are sealed in. This object contains the selection child, target, and parameters. When the Nsinvocation object is triggered, the message dispatch system (Message-dispatch) will personally take the message and assign it to the target object.

This step calls the following methods to forward the message:

-(void) Forwardinvocation: (nsinvocation*) invocation

This method can be implemented simply by changing the invocation target so that the message is invoked on the new target. However, this approach is equivalent to the method implemented by the "Redundancy recipient" scheme, so few people adopt such a simple implementation. The more useful way to do this is to change the message content in some way before triggering the message, such as appending another parameter, or changing the selector, and so on.

When implementing this method, if it is found that a call operation should not be handled by this class, a method with the same name as the superclass must be called. In this case, each class in the inheritance system has the opportunity to process this call request until nsobject. If the method of the NSObject class is called at the end, then the method also calls "Doesnotrecognizeselector:" to throw an exception, which indicates that the selector was eventually failed to be processed.

The recipient has the opportunity to process the message at each step. The more you step back, the greater the cost of processing the message. It is best to finish the process in the first step, so that the runtime system can cache the method. If an instance of this class later receives a selection of the same name, then there is no need to start the message forwarding process. If you want to pass the message to the recipient of the backup in the third step, you might as well advance the forwarding operation to the second step. Because the third step only modifies the invocation target, this change is easier to perform in the second step, or else you will have to create and process the complete nsinvocation.

iOS underlying development message mechanism (IV) message forwarding

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.