zoukankan      html  css  js  c++  java
  • ObjectiveC 2.0的运行时编程消息转发

    提到了resolveInstanceMethod,这个方法不仅在这里用,还用来实现消息的转发。

    消息的转发就是向对象发送一个它本身并没有实现的消息,在运行时确定它实际产生的行为。

    举个例子来说,一个Person对象,在运行时根据实际情况,决定是否响应fly这样的方法。如果条件具备,则fly被响应。否则,则不具备这样的方法。类似于AoP的做法。

    要实现消息转发,需要覆盖三个方法:

    1, resolveInstanceMethod(可选),这个方法为你提供了一个机会,在消息被发现本身没有在类中定义时你可以通过class_addMethod将它添加进去。如果你不这样做,不管你最终返回YES还是NO,程序都会jmp到下一个方法。

    2, –(NSMethodSignature*)methodSignatureForSelector: (SEL) sel;通过覆盖这个方法,可以将你要转发的消息的签名创建并返回。如果在这里你返回nil,那么就会直接抛出异常。如果返回一个签名,则程序会jmp到第三个方法。这里返回的方法签名,必须满足两个条件之一(方法名相同||输入参数相同).

    3, –(void)forwardInvocation:(NSInvocation * )anInvocation;在这里进行实际的方法调用。

     

    #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>

    void dynamicMethod(id self, SEL _cmd, float height);

    @interface Human : NSObject{

    float _height;

    }

    @property(retain, nonatomic) NSString * name;

    @property(readonly) float weight;

    @property float height;

    -(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.

    // 当赋值发生时,由于动态函数的全局性,可以访问其他全局变量,对象。所以更像一种链接机制

    }

    @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 isEqualToString:@"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) isEqualToString:@"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.

    //这里返回的消息,必须符合以下条件之一:

    //方法名相同

    //输入参数相同

    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"

    int main (int argc, 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;

  • 相关阅读:
    第十五篇:在SOUI中消息通讯
    为GDI函数增加透明度处理
    第十四篇:在SOUI中使用定时器
    第十三篇:在SOUI中使用有窗口句柄的子窗口
    第十二篇:SOUI的utilities模块为什么要用DLL编译?
    第十一篇:SOUI系统资源管理
    第十篇:扩展SOUI的控件及绘图对象(ISkinObj)
    第九篇:在SOUI中使用多语言翻译
    第八篇:SOUI中控件事件的响应
    Linked List Cycle
  • 原文地址:https://www.cnblogs.com/DamonTang/p/2760360.html
Copyright © 2011-2022 走看看