If an object is sent with an unrecoverable message without dynamic resolution and message Forwarding is not implemented, the following crash information will be triggered.
2014-07-30 15:47:54.434 MethodNotFind[1719:403] -[Person setName:]: unrecognized selector sent to instance 0x100121db0
The following is a test demo.
First, let's look at the definition of the person class.
# Import <Foundation/Foundation. h> @ class car; @ interface person: nsobject {car * car; // used to process messages that cannot be forwarded} @ property (copy) nsstring * Name;-(void) forwardinvocation :( nsinvocation *) aninvocation;-(void) print; @ end
Implementation of person. m
# Import "person. H "# import" car. H "@ implementation person @ dynamic name; // two functions: Tell the compiler not to create the get and setter methods for this attribute. tell the compiler not to create the instance variable used to implement the property // @ synthesize name = myname; // tell the compiler to help us create get and set methods in the class "person, create a member variable named myname-(ID) Init {If (Self = [Super init]) {car = [[Car alloc] init];} For the person class. return self;}-(void) dealloc {If (CAR) {[Car release]; car = nil;} [Super dealloc];} void dynamicmethodimp (ID self, sel _ cmd ){// Implementation .... nslog (@ "dynamic resolution method called");} + (bool) resolveinstancemethod :( SEL) SEL {nslog (@ "SEL is % @", nsstringfromselector (SEL )); // obtain the method name if (SEL ==@ selector (setname :)) {class_addmethod ([self class], Sel, (IMP) dynamicmethodimp, "[email protected]:"); return yes;} return [Super resolveinstancemethod: sel];} // the prerequisite for triggering this method is that + (bool) resolveinstancemethod :( SEL) returns no; otherwise, it will not be triggered. Subclass rewrite this method to forward messages to a specified object. You must also override-(nsmethodsignature *) methodsignatureforselector :( SEL) aselector. two conditions are missing. // Note: to respond to methods that your object does not itself recognize, you must override methodsignatureforselector: In addition to forwardinvocation :. the mechanism for forwarding messages uses information obtained from methodsignatureforselector: to create the nsinvocation object to be forwarded. your overriding method must provide an appropriate method signature for the given selector, either by Pre formulating one or by asking another object for one. -(void) forwardinvocation :( nsinvocation *) aninvocation {sel name = [aninvocation selector]; nslog (@ "> forwardinvocation for selector % @", nsstringfromselector (name )); if ([Car respondstoselector: Name]) {[aninvocation invokewithtarget: Car] ;}else {[self doesnotrecognizeselector: Name] ;}} // when the message is forwarded, this method obtains some information, creates an nsinvocation object, and sends the-(void) forwardinvocation :( nsinvocation *) aninvocation-(nsmethodsignature *) methodsignatureforselector :( SEL) aselector {return [Car instancemethodsignatureforselector: aselector];}-(void) print {// nslog (@ "% @", myname); // member variable name, can be specified by synthesize} @ end
The person class cannot respond-(void) setname :( nsstring *) when the name method is used, a car class is written for message forwarding,
Car. h
#import <Foundation/Foundation.h>@interface Car : NSObject{ NSString* myName;}-(void)setName:(NSString*) name;@end
Car. m implementation
# Import "car. H" @ implementation car-(void) setname :( nsstring *) name {nslog (@ "setname called in car"); If (! [Name isequal: myname]) {[myname release]; myname = Name ;}}@ end
When we implement dynamic method resolution and message forwarding, we will first call the dynamic method resolution and do not need to forward the message. If the selector is not actually implemented in the resolveinstancemethod implementation, no is returned. Then the message will be forwarded.
The following figure shows the success of the dynamic resolution method and the running result of message forwarding:
16:27:55. 072 methodnotfind [1774: 403] SEL is setname: 16:27:55. 073 methodnotfind [1774: 403] the dynamic resolution method is called.
Obviously, the dynamic resolution method is called and does not cause crash.
Comment out void dynamicmethodimp (ID self, Sel _ cmd) and + (bool) resolveinstancemethod :( SEL) SEL. Check the running result:
16:28:33. 343 methodnotfind [1786: 403]> forwardinvocation for selector setname: 16:28:33. 343 methodnotfind [1786: 403] setname is called in car
Obviously, message Forwarding is implemented without triggering crash.
Message sending process:
First, find the IMP corresponding to sel in the cache, method list, and parent class object and method list of the object. If the resolution mechanism of the dynamic method is not found and implemented, the resolution will be implemented. If the resolution mechanism of the dynamic method is not implemented or the resolution fails and the message forwarding mechanism is implemented, the message forwarding process will be entered.