cocoa动态方法决议及消息转发

cocoa动态方法决议及消息转发

大家好,又见面了,我是全栈君,今天给大家准备了Idea注册码。

全栈程序员社区此处内容已经被作者隐藏,请输入验证码查看内容
验证码:
请关注本站微信公众号,回复“验证码”,获取验证码。在微信里搜索“全栈程序员社区”或者“www_javaforall_cn”或者微信扫描右侧二维码都可以关注本站微信公众号。

假设给一个对象发送不能响应的消息,同一时候又没有进行动态方法决议,又没实现消息转发,那么就会引发以下的crash信息

2014-07-30 15:47:54.434 MethodNotFind[1719:403] -[Person setName:]: unrecognized selector sent to instance 0x100121db0

下面是測试的demo

先看看Person类的定义。

#import <Foundation/Foundation.h>
@class Car;
@interface Person : NSObject
{
    Car* car; //用来处理不能转发的消息
}

@property (copy)NSString* name;

- (void)forwardInvocation:(NSInvocation *)anInvocation;

-(void)print;
@end

Person.m的实现部分

#import "Person.h"
#import "Car.h"
@implementation Person


@dynamic name; //两个作用:告诉编译器不要创建该属性的get和setter方法.告诉编译器不要创建实现属性所用的实例变量

//@synthesize name=myName; //告诉编译器在Person这个类里面帮我们创建get和set方法,同一时候为我们得Person类创建一个成员变量叫myName



-(id)init
{
    if (self=[super init]) {
        car=[[Car alloc] init];
    }
    return self;
}

-(void)dealloc
{
    if (car)
    {
        [car release];
        car=nil;
    }
    [super dealloc];
}

void dynamicMethodIMP(id self, SEL _cmd)
{
    // implementation ....
    NSLog(@"动态决议方法被调用");
    
    
}

+ (BOOL)resolveInstanceMethod:(SEL)sel
{
    NSLog(@"sel is %@", NSStringFromSelector(sel)); //得到方法名
    if(sel == @selector(setName:)){
       class_addMethod([self class],sel,(IMP)dynamicMethodIMP,"v@:");
        return YES; 
    }
    

    return [super resolveInstanceMethod:sel];
}



// 这种方法触发的前提就是+ (BOOL)resolveInstanceMethod:(SEL)返回NO,否则将不会进行触发。 子类重写这种方法,能够把消息转给一个指定得对象。还有必需要重写- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector这种方法.两个条件缺一不可

//注意: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];
    }
   
    
 

}


//消息转发的时候这种方法会获取一些信息,去创建NSInvocation对象,给- (void)forwardInvocation:(NSInvocation *)anInvocation使用
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
    return [Car instanceMethodSignatureForSelector:aSelector];
}


-(void)print
{
   
  //  NSLog(@"%@",myName);//成员变量名字,能够由synthesize指定

}
@end

Person类不能响应-(void)setName:(NSString*) name方法时,写了一个Car类进行消息转发,

Car.h

#import <Foundation/Foundation.h>

@interface Car : NSObject
{
    NSString* myName;
}

-(void)setName:(NSString*) name;
@end

Car.m实现

#import "Car.h"

@implementation Car



-(void)setName:(NSString *)name
{
    
    NSLog(@"setName 在Car里面被调用");
    if (![name isEqual:myName])
    {
        [myName release];
        myName=name;
    }
}
@end

当我们实现了动态方法决议,又实现了消息转发,那么首先会调用动态方法决议,也不须要进行消息转发了。假设在 resolveInstanceMethod 的实现中没有真正为 selector 提供实现,并返回 NO。那么就会进行消息转发。

下面是实现了动态决议方法成功以及实现了消息转发的执行结果:

2014-07-30 16:27:55.072 MethodNotFind[1774:403] sel is setName:
2014-07-30 16:27:55.073 MethodNotFind[1774:403] 动态决议方法被调用

非常显然动态决议方法被调用了,不会引发crash。

把void dynamicMethodIMP(id self, SEL _cmd)和+ (BOOL)resolveInstanceMethod:(SEL)sel凝视之后。看看执行结果:

2014-07-30 16:28:33.343 MethodNotFind[1786:403]  >> forwardInvocation for selector setName:2014-07-30 16:28:33.343 MethodNotFind[1786:403] setName 在Car里面被调用

非常显然实现了消息转发,也没引发crash。

消息发送的过程:

首先在对象的类对象的 cache,method list 以及父类对象的 cache, method list 中依次查找 SEL 相应的 IMP。假设没有找到且实现了动态方法决议机制就会进行决议,假设没有实现动态方法决议机制或决议失败且实现了消息转发机制就会进入消息转发流程。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/117995.html原文链接:https://javaforall.net

赞 (0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Ubuntu 18.04 firefox浏览器装flash[通俗易懂]

    Ubuntu 18.04 firefox浏览器装flash[通俗易懂]进入http://get.adobe.com/cn/flashplayer/即flash官网(注意下载和系统浏览器相对应的包)在左边选择.tar.gz格式的文件然后解压  tar-zxvfinstall_flash_player_11_linux.x86_64.tar.gz进入解压后的usr文件夹,把libflashplayer.so文件放到路径/usr/lib/mozilla/…

    2022年6月8日
  • 软件测试用例常用七大方法

    软件测试用例常用七大方法第一:测试用例格式包括十大特点用例编号测试项测试标题用例属性重要级别:高中低预置条件测试输入操作步骤预期结果实际结果第二:等价类1,等价类定义2,等价类划分3,等价类划分规则4,进行等价类用例设计5,案例加以说明第三:边界值1,边界值的三点2,边界值应用场景3,边界值方法应用步骤第四:判定…

    2022年6月30日
  • Linux磁盘扩容 之 LVM 扩容之路

    Linux磁盘扩容 之 LVM 扩容之路引言众所周知,我们大多数服务都是跑在Linux上的,因为Linux命令行形式的特性,也导致了很多开发者只喜欢把Linux当做跑服务的机器,并不作为日常的使用。这样导致了我们只能记得常用的部署命令,但遇到一些复杂的Linux运维就不知如何下手了。这不,我这两天就遇到了服务器磁盘不足的问题,一开始只想Google一下快速搞定,结果还是得补补Linux中LVM的这块知识点才可以。为了方便后人快速扩容,特此记录。LVM是什么LVM(LogicalVolumeManager)翻译过来是逻辑卷管理器,大家可

    2022年6月20日
  • NSTimer用法

    NSTimer用法

    2021年8月26日
  • 黑盒测试用例测试方法

    黑盒测试用例测试方法黑盒测试用例设计方法一、等价类划分法等价类划分法是一种典型的、重要的黑盒测试方法,是指某个输入域的子集合。在该子集合中,所有的输入数据对于揭露软件中的错误都是等效的。等价类划分有效等价类和无效等价类例如:微信红包的例子【0.01-200】按数据范围划分:有效的:0.01-200(1)无效的:小于0.01(2)…

    2022年6月12日
  • 图形数字推理1000题及答案_小学奥数图形推理题

    图形数字推理1000题及答案_小学奥数图形推理题事情是这样滴!一个小伙伴在这两天提出一个问题如下:考虑到数字推理是浙江省考每年的必考题,图形题在去年的浙江省考中考查了四题。而图形题相较于分数数列、递推数列、多级数列等常见纯数字数列来说,在没有掌握一些常见技巧的前提下确实无从下手。这两天经过对图形题的系统性梳理发现其中有一些可操作的技巧与方法,希望能够帮助到即将踏入战场的浙江的小伙伴。当然,除了浙江的小伙伴之外,一些自主命题省份,如江苏、广东、吉…

    2022年9月9日

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号