Objective-C 2.0 中增加了@dynamic 指令,表示变量对应的属性访问器方法,是动态实现的,你需要在NSObject 中继承而来的+(BOOL) resolveInstanceMethod:(SEL) sel 方法中指定动态实现的方法或者函数。

Person.h:

[cpp]  view plain copy
  1. @interface Person : NSObject{
  2. NSString *name;
  3. float weight;
  4. }
  5. -(Person*) initWithWeight: (int) weight;
  6. @property (retain,readwrite) NSString* name;
  7. @property (readonly)float weight;
  8. @property float height;
  9. -(void) print: (NSString*) str;
  10. @end

Person.m:

[cpp]  view plain copy
  1. void dynamicMethod(id self,SEL _cmd,float w){
  2. printf("dynamicMethod-%s\n",[NSStringFromSelector(_cmd)
  3. cStringUsingEncoding:NSUTF8StringEncoding]);
  4. printf("%f\n",w);
  5. }
  6. @implementation Person
  7. @synthesize name;
  8. @synthesize weight;
  9. @dynamic height;
  10. -(Person*) initWithWeight: (int) w{
  11. self=[super init];
  12. if (self) {
  13. weight=w;
  14. }
  15. return self;
  16. }
  17. -(void) print: (NSString*) str{
  18. NSLog(@"%@%@",str,name);
  19. }
  20. +(BOOL) resolveInstanceMethod: (SEL) sel{
  21. NSString *methodName=NSStringFromSelector(sel);
  22. BOOL result=NO;
  23. //看看是不是我们要动态实现的方法名称
  24. if ([methodName isEqualToString:@"setHeight:"]) {
  25. class_addMethod([self class], sel, (IMP) dynamicMethod,
  26. "v@:f");
  27. result=YES;
  28. }
  29. return result;
  30. }
  31. -(void) dealloc{
  32. [self setName:nil];
  33. [super dealloc];
  34. }
  35. @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详细介绍相关推荐

  1. 【转】ARM 之七 主流编译器(armcc、iar、gcc for arm、LLVM(clang))详细介绍

    转自:ARM 之七 主流编译器(armcc.iar.gcc for arm.LLVM(clang))详细介绍_itexp-CSDN博客_armcc 必备   在讲解各编译器之前,必须先了解一下以下文件 ...

  2. Arduino的详细介绍(基于Mega2560)

    了解Arduino的最好平台当然是官网,我相信官网肯定不会遗漏自己产品最有特色的东西,因此以它为参考绝对没错.另外,必要部分辅助以百科,以及各位广大亲爱博友的资料(就不一一列举了,在此谢过).本文以A ...

  3. IPv6下DHCPv6协议(RFC3315)详细介绍

    DHCPv6 详细介绍 前言 一.基础部分 二.DHCPv6的进阶 1.相关术语/概念(Term) 2.几个相关的算法/规则 3.Message交换过程详述 4.基础的几个option介绍(RFC33 ...

  4. 详细介绍微软SQL Server 2008

    SQL Server 2008是一个重大的产品版本,它推出了许多新的特性和关键的改进,使得它成为至今为止的最强大和最全面的SQL Server版本.这篇文章详细介绍了Microsoft SQL Ser ...

  5. Android manifest文件中的标签详细介绍

    Android manifest文件中的标签详细介绍 概要 每一个Android应用都应该包含一个manifest文件,即AndroidManifest.xml.它包含了程序运行的一些必备信息,比如: ...

  6. 【目标检测】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 单阶段目标 ...

  7. 什么是UPNP协议:UPNP协议作用及启用路由器UPNP支持的方法详细介绍

    目录 [隐藏] UPNP简介 基本概念 官网解释 以下是微软官方网站对UPnP的解释: 以下是BC官方网站对UPnP的解释: UPnP是用来干什么的? 经典应用 网络地址转换 NAT 穿越技术 实际应 ...

  8. 【ZYNQ】IP核_VDMA的详细介绍

    VDMA的特点总结: 1.AXI VDMA核心支持为32位地址空间寻址最多32个帧缓冲区,为32位以上地址空间寻址多达8个帧缓冲: 2.AXI VDMA核心支持可选的数据重新调整引擎(DRE).DRE ...

  9. ES6详细介绍及使用

    ES6详细介绍及使用 一. ES6概念及发展史 1.ES6概念 以前学习JavaScript的时候,对ES5是有了解过的,但是在学习Vue的时候,就会发现有很多新的写法是ES6中的,真是让人捉急.所以 ...

最新文章

  1. qiime2安装和使用案例
  2. 2018年黑龙江各口岸进口俄大豆80.3万吨 同比增长60.1%
  3. virtualenv使用说明
  4. MySql 日志查看与设置
  5. Powershell 自定义输出列,两个例子
  6. OpenCv cv::Mat 转 IplImage 函数
  7. php返回一个变量,PHP从另一个文件获取变量
  8. Lucence.Net学习+盘古分词
  9. 网络电话---异常处理01
  10. 9个适合web开发人员的CSS工具
  11. HDU1573 X问题【扩展欧几里得算法】
  12. Buck电源设计和电感电容参数介绍
  13. Excel 分组显示(COUNTIF 函数实现)
  14. 每天一个npm包 之 qs
  15. 《吕鑫:VC++6.0就业培训宝典之MFC视频教程》学习笔记 -- 第五章对话框组合
  16. 【flutter】篇8-2:Animations
  17. 经济学原理笔记(一)
  18. 利用ADB 协议建立PC与手机端本地unix套接字的连接
  19. 主从复制MySQL的安装和用数据库中间件MyCat实现分库分表、读写分离
  20. 下列各项中,属于计算机网络功能的有电算化,2017会计电算化题库(必考的)

热门文章

  1. oracle中删除yuj_[转载]Oracle中删除表操作trunc delete和drop的说明
  2. 国内外众筹平台的对比分析
  3. 基于C语言的infineon TC377的CAN通信代码的参考资料
  4. MSComm控件的几个疑难问题汇总
  5. 房地产CRM实践进入成长期
  6. 【Java设计模式】状态模式
  7. 新算力下的2019 AI
  8. Python---字符串编码和判断开头结尾
  9. leaflet 示例教程100+ 目录
  10. PLC 西门子smart200 锁机 分期期付款 动态验证码