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


相关推荐

  • 树的先序遍历对应二叉树的_先序遍历输入一个二叉树

    树的先序遍历对应二叉树的_先序遍历输入一个二叉树笔试特别喜欢考这种题。先说一下思路。首先,需要明白前序、中序、后序遍历:①前序:根→左→右②中序:左→根→右③后序:左→右→根仅明白这个是不行的,还需要技巧。对于标题中的问题,我们很容易判断根节点是A,A的右节点是B,A的左边有CDFEGH,如下图:然后,将问题进行分解。去掉了AB结点之后,问题可分解如下:按照同样的套路,我们可以画出子问题的数大大概结构,如下图:与第一步画…

    2022年9月3日
    3
  • 安捷伦频谱仪的使用方法图解_安捷伦E4402B频谱仪使用说明

    安捷伦频谱仪的使用方法图解_安捷伦E4402B频谱仪使用说明标签:安捷伦仪器使用说明安捷伦仪器使用说明本资料为安捷伦频谱仪器使用说明,资料用于学习交流不能以任何形式商用。文档内容节选AgilentE4402BESAESeriesSpectrumAnalyzer使用方法简介宁波之猫2009617…

    2022年8月11日
    4
  • snmp协议分析_snmp协议工作原理

    snmp协议分析_snmp协议工作原理介绍Snmp协议为简单网络管理协议(SimpleNetworkManagementProtocol),属于应用层协议,传输层使用UDP协议,主要用于网络设备的管理。Snmp协议分为snmp管理站(client端)和snmp代理(server端),snmp管理站通过udp协议向snmp代理发送请求消息,当snmp代理收到请求消息后,返回snmp管理站需要的内容。snmp消息全部通过UDP端…

    2022年10月17日
    0
  • 回归分析模型推广_案例分析的意义

    回归分析模型推广_案例分析的意义这个项目呢,就不需要我们做很多的数据清洗的工作了,因为我们手里的数据基本已经做好数据清洗了,我们主要需要做的就是数据可视化和文本挖掘工作。下面我们来一一介绍一下。目录1业务背景1.1分析流程概述1.2市场分类1.3产品生命周期1.4产品结构-波士顿矩阵(BCGMatrix)1.5处理项目需求的基本思路1.6项目需求例子1.7项目背景&产品架构1.8数据说明2驱虫市场的潜力分析2.1分析目的&加载数据2.1.1分析目的2.1.2加载数据2.2清洗&补全数

    2022年10月2日
    0
  • iDB-数据库自动化运维平台

    iDB-数据库自动化运维平台数据库,MySQL,自动化运维,AutoDDL,刷库,帐号授权,审核,回滚提纲:

    2022年5月13日
    130
  • concat效率 mysql_Mysql常用函数之Concat函数

    concat效率 mysql_Mysql常用函数之Concat函数本篇文章主要介绍了MySQL中concat函数的用法(连接字符串),在命令行模式下进行测试。1.MySQL中concat函数使用方法:CONCAT(str1,str2,…)返回结果为连接参数产生的字符串。如有任何一个参数为NULL,则返回值为NULL。注意:(1)如果所有参数均为非二进制字符串,则结果为非二进制字符串。(2)如果自变量中含有任一二进制字符串,则结果为一个二进制字符串。MySQ…

    2022年5月5日
    55

发表回复

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

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