I. When is the message forwarding mechanism sent?
Solution: 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.
Example:-[__nscfnumber lowercasestring]: Unrecognized selector sent to instance 0x87
This exception is thrown by NSOBJC's "Doesnotrecognizeselector" method, which indicates that the message receiver is of type _ _nscfnumber, and that the recipient cannot understand the selector named LowerCaseString.
Two. Why should I use message forwarding?
Solution: 1. Obj-c used to be a variety of happy, such as now there is a case: there is a class, we want it to respond to a message, but this class does not have a corresponding method, and you can not rewrite/inherit this class. At this point, we might think, can you dynamically add a method to a class? Thanks to Obj-c, it takes just a few steps to achieve it.
2. When using @property definition, with @dynamic implementation, will use the message to forward.
3. When a method is not implemented, a message forwarding mechanism is invoked.
Before call:
.-Geneva- - xx: to:42.074messageforwarding[927:70955]-[messageforwarding running]: Unrecognized selector sent to instance0x7fee615169c0 .-Geneva- - xx: to:42.076messageforwarding[927:70955] * * * * terminating app due to uncaught exception'nsinvalidargumentexception', Reason:'-[messageforwarding running]: Unrecognized selector sent to instance 0x7fee615169c0'FirstThrowCall stack: (0Corefoundation0x00000001106dfe65__exceptionpreprocess +1651LIBOBJC. A.dylib0x0000000110158debObjc_exception_throw + -2Corefoundation0x00000001106e848d-[nsobject (NSObject) Doesnotrecognizeselector:] +2053Corefoundation0x000000011063590a___forwarding___ +9704Corefoundation0x00000001106354b8_cf_forwarding_prep_0 + -5Messageforwarding0x000000010fc590d3-[viewcontroller Viewdidload] + About6UIKit0x0000000110c22f98-[uiviewcontroller Loadviewifrequired] +11987UIKit0x0000000110c232e7-[uiviewcontroller View] + -8UIKit0x0000000110af9ab0-[uiwindow Addrootviewcontrollerviewifpossible] + A9UIKit0x0000000110afa199-[uiwindow _sethidden:forced:] +282TenUIKit0x0000000110b0bc2e-[uiwindow Makekeyandvisible] + the OneUIKit0x0000000110a84663-[uiapplication _callinitializationdelegatesformainscene:transitioncontext:] +4131 AUIKit0X0000000110A8ACC6-[uiapplication _runwithmainscene:transitioncontext:completion:] +1760 -UIKit0x0000000110a87e7b-[uiapplication Workspacedidendtransaction:] +188 -Frontboardservices0x000000011345b754-[fbsserialqueue _performnext] +192 theFrontboardservices0x000000011345bac2-[fbsserialqueue _performnextfromrunloopsource] + $ -Corefoundation0x000000011060ba31__cfrunloop_is_calling_out_to_a_source0_perform_function__ + - -Corefoundation0x000000011060195c__cfrunloopdosources0 +556 -Corefoundation0x0000000110600e13__cfrunlooprun +867 +Corefoundation0x0000000110600828Cfrunlooprunspecific +488 -UIKit0X0000000110A877CD-[uiapplication _run] +402 +UIKit0x0000000110a8c610Uiapplicationmain +171 AMessageforwarding0x000000010fc59a1fMain +111 atLibdyld.dylib0x0000000112e1b92dStart +1) libc++abi.dylib:terminating with uncaught exception of type NSException
After the call:
22.577 -xx: messageforwarding[950: 73397] message. string= Kun kun, message.number=, message.date=2033-08 :£ º +0000
Three. What is the process of message forwarding?
1. Process
Solution: The first stage: first consult the receiver, the class to see if it can dynamically add methods to deal with the current "unknown selector" (unknown selector) This is called dynamic Method Resolution (resolution).
Phase II: Involving "complete message forwarding mechanism" (full forwarding mechanism) if the run-time system has completed the first phase, then the recipient cannot respond to the message containing the selector in a dynamically new way. At this point, the runtime system requests the recipient to handle the message-related method calls in other ways. This breaks down two small steps, first, ask the recipient to see if there are any other objects that can handle the message. If so, the run-time system will
Transfer the message to the object, and the message is forwarded to the end, as usual. Without the "replacement Recever", the 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 Make it try to resolve the message that is not currently being processed.
2. The method is as follows:
+ (BOOL) Resolveinstancemethod: (SEL) sel;
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.
If the method that has not been implemented is not an instance method but a class method, then the runtime system calls another method, which is similar to the + (bool) Resolveinstancemethod: (SEL) SEL is called: + (BOOL) Resolveclassmethod :(sel) sel.
3. Conditions of Use
The implementation of the relevant method code has been written, just waiting for the runtime to plug in the dynamic in the class. This scenario is commonly used to implement @dynamic properties, such as the ability to access Nsmanagedobjects object properties in the CoreData framework, because the access methods required to implement these properties can be determined at compile time.
4. Code Advance
The following code shows how to implement the @dynamicnt property with "Resolveinstancemethod:".
#import<Foundation/Foundation.h>@interfaceMessageforwarding:nsobjectIDAutodictionarygetter (IDSelf,sel _cmd);//Setter MethodvoidAutodictionarysetter (IDSelf,sel _cmd,IDValue);//Getter Method/** * Dynamic parsing method * * @param sel Unknown Selector * * @return If this class can add an instance method to handle this selector*/+(BOOL) Resolveinstancemethod: (SEL) sel; @property (nonatomic, strong) NSString*string; @property (nonatomic, strong) NSNumber*Number ; @property (nonatomic, strong) NSDate*date; @property (nonatomic, Strong)IDOpaqueobject;@end#import "MessageForwarding.h"#import<objc/runtime.h>@interfacemessageforwarding () @property (nonatomic, strong) Nsmutabledictionary*Backingstore;@end@implementationmessageforwarding@dynamicstring, Date,number,opaqueobject;#pragmaMark Getter and setterIDAutodictionarygetter (IDSelf,sel _cmd) { //Get The backing store from the objectMessageforwarding *typeself = (messageforwarding *) Self; Nsmutabledictionary*backingstore =Typeself.backingstore; //The key is simply the selector nameNSString *key =Nsstringfromselector (_cmd); //return the value return[Backingstore Objectforkey:key];}voidAutodictionarysetter (IDSelf,sel _cmd,IDvalue) { //Back the backing store from the objectMessageforwarding *kunkunself = (messageforwarding *) Self; Nsmutabledictionary*backstore =Kunkunself.backingstore; /** The selector will is for example, "Setopaqueobject"//With this selector for example, "setopaqueobject" We need to remove the "set" , ":" and lowercase the first//We must remove the set and: and the initial letter of the lowercase letters of the the remainder*/NSString*selectorstring =Nsstringfromselector (_cmd); Nsmutablestring*key =[selectorstring mutablecopy]; //Remove the:at the end//in the last delete:[Key Deletecharactersinrange:nsmakerange (Key.length-1,1)]; //Remove the "set" prefix[Key Deletecharactersinrange:nsmakerange (0,3)]; //lowercase The first characterNSString *lowercasefirstchar = [[Key substringtoindex:1] lowercasestring]; [Key Replacecharactersinrange:nsmakerange (0,1) Withstring:lowercasefirstchar]; if(value) {[Backstore setobject:value forkey:key]; }Else{[Backstore removeobjectforkey:key]; }}#pragmainit-(instancetype) init{if(self =[Super Init]) {_backingstore=@{}.mutablecopy; } returnSelf ;}#pragmaMark message forwarding messages forwarding mechanism +(BOOL) Resolveinstancemethod: (SEL) sel{//message into a stringNSString *selectorstring =nsstringfromselector (SEL); //if (/**selector is from a @dynamic property*/) { if([selectorstring Hasprefix:@"Set"]) {Class_addmethod (Self,sel, (IMP) Autodictionarysetter,"[Email protected]:@"); }Else{Class_addmethod (self, SEL, (IMP) Autodictionarygetter,"@@:"); } returnYES; // }// //return [Super Resolveinstancemethod:sel];}@end
5. 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 forward this message to other recipients for processing, as follows:
/* * * The recipient of the redundancy is called when it is not processed for the first time. Resolveinstancemethod: (SEL) SEL, please note that we are unable to manipulate the message forwarded by this step, and if you want to modify the message content before sending it to the recipient of the redundancy, Then you have to do it through the full message forwarding mechanism. * * @param aselector Message * * */
6. Complete message forwarding
-(ID) forwardingtargetforselector: (SEL) aselector; /* * * full message forwarding, when triggering a Nsinvocation object, the "Message dispatch system" (Messages dispatch systems) will personally take the message and assign it to the target object **/
The whole process of message forwarding
Resolveinstancemethod-> returns YES--the message has been processed
Forwardingtargetforselector---receive the corresponding value---> Message processed
--Return nil-->forwardinvocation--message processed
---> Messages not processed
Introduction to the message forwarding mechanism