When talking about dynamic attributes in Article 7, we mentioned resolveinstancemethod. This method is not only used here, but also used to forward messages.
Message Forwarding is to send a message that is not implemented to an object and determine its actual behavior at runtime.
For example, a person object determines whether to respond to the fly method at runtime based on actual conditions. If conditions are met, fly is responded. Otherwise, this method is not available. Similar to AOP.
To Implement Message forwarding, three methods are required:
1. resolveinstancemethod (Optional). This method provides an opportunity for you to add a message to the class when it is discovered that it is not defined in the class. If you do not do this, no matter whether you finally return yes or no,ProgramJMP to the next method.
2,-(nsmethodsignature *) methodsignatureforselector: (SEL) SEL; By overwriting this method, you can create and return the signature of the message you want to forward. If you return nil here, an exception is thrown directly. If a signature is returned, the program uses JMP to the third method. The method signature returned here must meet one of the two conditions (the method name is the same | the input parameter is the same ).
3,-(void) forwardinvocation :( nsinvocation *) aninvocation; call the actual method here. Refer to the followingCode:
# Import <Foundation/Foundation. h>
# Import " Human. h "
@ Interface plane: nsobject
-( Void ) Fly :( human *) P;
-( Int ) Fly1;
-( Void ) Fly2 :( human *) P withbird :( nsstring *) birdname;
@ End
# Import"Plane. h"
@ Implementation plane
-( Void ) Fly :( human *) P {
Nslog ( @" Fly with a guy whose information is \ " % @\ "" , [P description]);
Nslog ( @" Fly ...... " );
}
-( Int ) Fly1 {
Nslog ( @" I can fly in plane for fly1 " );
Return 0 ;
}
-( Void ) Fly2 :( human *) P withbird :( nsstring *) birdname {
Nslog ( @" Fly with a guy whose information is \ " % @\ "" , [P description]);
Nslog ( @" Fly ...... bird: '% @'. " , Birdname );
}
@ End
# Import <Foundation/Foundation. h>
VoidDynamicmethod (ID self, Sel _ cmd,FloatHeight );
@ Interface human: nsobject {
Float_ Height;
}
@ Property (retain, nonatomic) nsstring * Name;
@ Property (Readonly)FloatWeight;
@ PropertyFloatHeight;
-(ID) initwithweight :(Float) Weight;
-(Nsstring *) description;
@ End
# Import <objc/runtime. h>
# Import " Human. h "
# Import " Plane. h "
Void Dynamicmethod (ID self, Sel _ cmd, Float Height ){
Nslog ( @" Dynamicmethod: % @ " , Nsstringfromselector (_ cmd ));
// Here is a question. How to Implement the statements to assign the property of ID (human. Height );
// Looks like the dynamic property is just for linkage.
// When a value assignment occurs, other global variables and objects can be accessed due to the global nature of the dynamic function. So it is more like a link mechanism.
}
@ Implementation human
@ Synthesize name;
@ Synthesize weight;
@ Dynamic height;
-(ID) initwithweight :( Float ) W {
If (Self = [Super init]) {
Weight = W;
}
Return Self;
}
-(Nsstring *) Description {
Return [Nsstring stringwithformat: @" The human whose name is \ " % @\ " . Weight is [% F]. height is [% F] " ,
Self. Name, self. Weight, self. Height];
}
-( Float ) Height {
Return _ Height;
}
-( Void ) Fly2 {
Nslog ( @" Yes I can fly in 2! " );
}
+ (Bool) resolveinstancemethod :( SEL) SEL {
Nsstring * method = nsstringfromselector (SEL );
If ([Method ispolictostring: @" Setheight: " ]) {
Class_addmethod ([self Class ], Sel, (IMP) dynamicmethod, " V @: F " );
}
Return [Super resolveinstancemethod: sel];
}
-(Nsmethodsignature *) methodsignatureforselector :( SEL) selector {
Nsmethodsignature * Signature = [Super methodsignatureforselector: Selector];
If (! Signature & [nsstringfromselector (selector) isw.tostring: @" Fly " ]) {
// Signature = [[self class] instancemethodsignatureforselector: @ selector (fly2)];
Sel newsel = nsselectorfromstring ( @" Fly1 " ); // Will OK.
// Sel newsel = nsselectorfromstring (@ "Fly :"); // Will OK.
// Sel newsel = nsselectorfromstring (@ "fly2: withbird "); // Will wrong.
// The returned message must meet one of the following conditions:
// Same method name
// The input parameters are the same.
If ([Plane instancesrespondtoselector: newsel]) {
Signature = [Plane instancemethodsignatureforselector: newsel];
}
}
Return Signature;
}
-( Void ) Forwardinvocation :( nsinvocation *) aninvocation {
Nsstring * selname = nsstringfromselector ([aninvocation selector]);
Nsmethodsignature * Sig = [aninvocation methodsignature];
Nslog ( @" The signature % @ " , [Nsstring stringwithcstring: [sig methodreturntype] encoding: nsutf8stringencoding]);
If ([Selname isequaltostring: @" Fly " ]) {
Plane * P = [[Plane alloc] init];
Sel newsel = nsselectorfromstring ( @" Fly: " );
IMP imp = [p methodforselector: newsel];
IMP (p, newsel, self );
[P release];
}
}
-( Void ) Dealloc {
[Self setname: Nil];
[Super dealloc];
}
@ End
# Import <Foundation/Foundation. h>
# Import <objc/runtime. h>
# Import"Human. h"
# Import"Plane. h"
IntMain (IntArgc,Const Char* Argv [])
{
@ Autoreleasepool {
// Insert code here...
Human * H = [[Human alloc] initwithweight: 17.3 ];
H. Name = @" Chris " ;
H. Height = 18.0 ;
Nslog ( @" % @ " , [H description]);
[H Fly];
[H release];
H = nil;
}}