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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • spin_lock &amp; mutex_lock的差别?

    spin_lock &amp; mutex_lock的差别?

    2021年12月7日
    46
  • Python中if __name__ == ‘__main__‘:的作用和原理「建议收藏」

    Python中if __name__ == ‘__main__‘:的作用和原理「建议收藏」if__name__==’__main__’:的作用一个python文件通常有两种使用方法,第一是作为脚本直接执行,第二是import到其他的python脚本中被调用(模块重用)执行。因此if__name__==’main’:的作用就是控制这两种情况执行代码的过程,在if__name__==’main’:下的代码只有在第一种情况下(即文件作为脚本直接执行)才会…

    2022年6月1日
    31
  • python fabric实现远程操作和部署

    python fabric实现远程操作和部署

    2021年12月2日
    48
  • modelsim-win64-10.4-se 破解攻略

    modelsim-win64-10.4-se 破解攻略在实验室换了新的win10系统,原来的quartus9.0在win10上安装不成功,没办法只能换成13.1版本,已经安装可用,下面是与其配合的modelsim-win64-10.4-se的破解攻略,安装教程可以去看正点原子的FPGA开发手册,写的很详细,但是没有讲破解方法,下面是可用的破解方法:软件安装好了却不能用,想必大家都有过这样的痛苦和无奈。这款软件的破解花了我整整一个下午的时间…

    2022年5月24日
    166
  • 测试用例附实例[通俗易懂]

    一、测试用例的概念测试用例是测试过程中很重要的一类文档,它是测试工作的核心,是一组在测试时输入和输出的标准,是软件需求的具体对照。二、测试用例的作用检验软件是否满足客户需求 测试人员的工作量的一种体现 展示测试用例的设计思路三、测试用例的内容测试用例八个基本项是:测试用例编号、测试项目、测试标题、重要级别、预置条件、输入、操作步骤、预期输出(不同公司的测试用例内容不尽相同…

    2022年4月13日
    55
  • 用npm安装yarn(买电脑主要看哪些配置)

    写在前面:前端开发常需要配合后台同时进行,在没有后台的情况下,服务器通信和获取数据进行页面渲染就无法进行。使用Javascript编写的Node.js服务器,对于前端开发人员来说,可以免去对学习服务器脚本语言的学习成本,能够在短时间构建一套完整的、高效的Web服务。NPM(NodePackageManager)作为Node.js的依赖包管理器便应运而生,而YARN则是针对NPM的一些不太优…

    2022年4月10日
    41

发表回复

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

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