@dynamic详细介绍
Objective-C 2.0 中增加了@dynamic 指令,表示变量对应的属性访问器方法,是动态实现的,你需要在NSObject 中继承而来的+(BOOL) resolveInstanceMethod:(SEL) sel 方法中指定动态实现的方法或者函数。
Person.h:
- @interface Person : NSObject{
- NSString *name;
- float weight;
- }
- -(Person*) initWithWeight: (int) weight;
- @property (retain,readwrite) NSString* name;
- @property (readonly)float weight;
- @property float height;
- -(void) print: (NSString*) str;
- @end
Person.m:
- void dynamicMethod(id self,SEL _cmd,float w){
- printf("dynamicMethod-%s\n",[NSStringFromSelector(_cmd)
- cStringUsingEncoding:NSUTF8StringEncoding]);
- printf("%f\n",w);
- }
- @implementation Person
- @synthesize name;
- @synthesize weight;
- @dynamic height;
- -(Person*) initWithWeight: (int) w{
- self=[super init];
- if (self) {
- weight=w;
- }
- return self;
- }
- -(void) print: (NSString*) str{
- NSLog(@"%@%@",str,name);
- }
- +(BOOL) resolveInstanceMethod: (SEL) sel{
- NSString *methodName=NSStringFromSelector(sel);
- BOOL result=NO;
- //看看是不是我们要动态实现的方法名称
- if ([methodName isEqualToString:@"setHeight:"]) {
- class_addMethod([self class], sel, (IMP) dynamicMethod,
- "v@:f");
- result=YES;
- }
- return result;
- }
- -(void) dealloc{
- [self setName:nil];
- [super dealloc];
- }
- @end
这里我们对于接口中的height在实现类中使用了@dynamic指令,紧接着,你需要指定一个函数或者其他类的方法作为height的setter、getter方法的运行时实现。为了简单,我们指定了Person.m中定义的函数(注意这是C语言的函数,不是Objective-C的方法)dynamicMethod
作为height的setter方法的运行时实现。被指定为动态实现的方法的dynamicMethod的参数有如下的要求:
A.第一个、第二个参数必须是id、SEL;
B.第三个参数开始,你可以按照原方法(例如:setHeight:(float))的参数定义。
再接下来,你需要覆盖NSObject 的类方法resolveInstanceMethod,这个方法会把需要动态实现的方法(setHeight:)的选择器传递进来,我们判断一下是否是需要动态实现的选择器,如果是就把处理权转交给dynamicMethod。如何转交呢?这里我们就要用到运行时函数class_addMethod(Class,SEL,IMP,char[])。
运行时函数位于objc/runtime.h,正如名字一样,这里面都是C 语言的函数。按照这些函数的功能的不同,主要分为如下几类:操作类型、操作对象、操作协议等。大多数的函数都可以通过名字看出是什么意思,例如:class_addProtocol 动态的为一个类型在运行时增加协议、objc_getProtocol 把一个字符串转换为协议等。具体这些运行时函数都是做什么用的,你可以参看Apple 官方页面:
http://developer.apple.com/library/ios/documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html#//apple_ref/doc/uid/TP40001418
言归正传,我们来解释一下这里需要用到的class_addmethod 方法,这个方法有四个参数,Class 表示你要为哪个类型增加方法,SEL 参数表示你要增加的方法的选择器,IMP 表示你要添加的方法的运行时的具体实现的函数指针。其实在这里你能够看出SEL 并不能在运行时找到真正要调用的方法,IMP 才可以真正的找到实现方法的。
在讲解第四个参数char[]之前,我们先看一下第一篇文档中提到的@encode 指令,在把任意非Objective-C 对象类型封装为NSValue 类型的时候使用到了@encode 指令,但当时我们没有详细说明这个指令的含义。实际上@encode()可以接受任何类型,Objective-C 中用这个指令做类型编码,它可以把任何一个类型转换为字符串,譬如:void 类型被编码之后为v,对象类型为@,SEL 类型为:等,具体的你可以参看Apple 官方页面关于Type Encoding 的描述:
http://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html#//apple_ref/doc/uid/TP40008048-CH100-SW
现在我们来正式的看以下第四个参数v@:f 的含义,它描述了IMP 指向的函数的描述信息,按照@encode 指令编译之后的字符说明,第一个字符v 表示返回值为void,剩余的字符为dynamicMethod 函数的参数描述,@表示第一个参数id,:自然就是第二个参数SEL,f 就是第三个参数float。由于前面说过动态方法的实现的前两个参数必须是id、SEL,所以第四个参数中的字符串的第二、三个字符一定是@:。我们看到resolveInstanceMethod 方法的返回值为BOOL,也就是这个方法返回YES 表示找到了动态方法的具体实现,否则就表示没有在运行时找到真实的实现,程序就汇报错。
经过了上面的处理,Objective-C 的运行时只要发现你调用了@dynamic 标注的属性的setter、getter 方法,就会自动到resolveInstanceMethod 里去寻找真实的实现。这也就是说你在main.m 中调用peson.height 的时候,实际上dynamicMethod 函数被调用了。实际上除了@dynamic 标注的属性之外,如果你调用了类型中不存在的方法,也会被
resolveInstanceMethod 或者resolveClassMethod 截获,但由于你没有处理,所以会报告不能识别的消息的错误。你可能在感叹一个@dynamic 指令用起来真是麻烦,我也是研究了半天Apple 官方的晦涩的鸟语才搞明白的。不过好在一般Objective-C 的运行时编程用到的并不多,除非你想设计一个动态化的功能,譬如:从网络下载一个升级包,不需要退出原有的程序,就可以动态的替换掉旧的功能等类似的需求。
@dynamic详细介绍相关推荐
- 【转】ARM 之七 主流编译器(armcc、iar、gcc for arm、LLVM(clang))详细介绍
转自:ARM 之七 主流编译器(armcc.iar.gcc for arm.LLVM(clang))详细介绍_itexp-CSDN博客_armcc 必备 在讲解各编译器之前,必须先了解一下以下文件 ...
- Arduino的详细介绍(基于Mega2560)
了解Arduino的最好平台当然是官网,我相信官网肯定不会遗漏自己产品最有特色的东西,因此以它为参考绝对没错.另外,必要部分辅助以百科,以及各位广大亲爱博友的资料(就不一一列举了,在此谢过).本文以A ...
- IPv6下DHCPv6协议(RFC3315)详细介绍
DHCPv6 详细介绍 前言 一.基础部分 二.DHCPv6的进阶 1.相关术语/概念(Term) 2.几个相关的算法/规则 3.Message交换过程详述 4.基础的几个option介绍(RFC33 ...
- 详细介绍微软SQL Server 2008
SQL Server 2008是一个重大的产品版本,它推出了许多新的特性和关键的改进,使得它成为至今为止的最强大和最全面的SQL Server版本.这篇文章详细介绍了Microsoft SQL Ser ...
- Android manifest文件中的标签详细介绍
Android manifest文件中的标签详细介绍 概要 每一个Android应用都应该包含一个manifest文件,即AndroidManifest.xml.它包含了程序运行的一些必备信息,比如: ...
- 【目标检测】56、目标检测超详细介绍 | Anchor-free/Anchor-based/Backbone/Neck/Label-Assignment/NMS/数据增强
文章目录 1.双阶段和单阶段目标检测器 1.1 双阶段目标检测器 1.1.1 R-CNN 1.1.2 SPP 1.1.3 Fast R-CNN 1.1.4 Faster R-CNN 1.2 单阶段目标 ...
- 什么是UPNP协议:UPNP协议作用及启用路由器UPNP支持的方法详细介绍
目录 [隐藏] UPNP简介 基本概念 官网解释 以下是微软官方网站对UPnP的解释: 以下是BC官方网站对UPnP的解释: UPnP是用来干什么的? 经典应用 网络地址转换 NAT 穿越技术 实际应 ...
- 【ZYNQ】IP核_VDMA的详细介绍
VDMA的特点总结: 1.AXI VDMA核心支持为32位地址空间寻址最多32个帧缓冲区,为32位以上地址空间寻址多达8个帧缓冲: 2.AXI VDMA核心支持可选的数据重新调整引擎(DRE).DRE ...
- ES6详细介绍及使用
ES6详细介绍及使用 一. ES6概念及发展史 1.ES6概念 以前学习JavaScript的时候,对ES5是有了解过的,但是在学习Vue的时候,就会发现有很多新的写法是ES6中的,真是让人捉急.所以 ...
最新文章
- qiime2安装和使用案例
- 2018年黑龙江各口岸进口俄大豆80.3万吨 同比增长60.1%
- virtualenv使用说明
- MySql 日志查看与设置
- Powershell 自定义输出列,两个例子
- OpenCv cv::Mat 转 IplImage 函数
- php返回一个变量,PHP从另一个文件获取变量
- Lucence.Net学习+盘古分词
- 网络电话---异常处理01
- 9个适合web开发人员的CSS工具
- HDU1573 X问题【扩展欧几里得算法】
- Buck电源设计和电感电容参数介绍
- Excel 分组显示(COUNTIF 函数实现)
- 每天一个npm包 之 qs
- 《吕鑫:VC++6.0就业培训宝典之MFC视频教程》学习笔记 -- 第五章对话框组合
- 【flutter】篇8-2:Animations
- 经济学原理笔记(一)
- 利用ADB 协议建立PC与手机端本地unix套接字的连接
- 主从复制MySQL的安装和用数据库中间件MyCat实现分库分表、读写分离
- 下列各项中,属于计算机网络功能的有电算化,2017会计电算化题库(必考的)