iOS中 @synthesize 和 @dynamic 的区别

@synthesize 实际的意义就是 自动生成属性的setter和getter方法。

@dynamic 就是要告诉编译器,代码中用@dynamic修饰的属性,其getter和setter方法会在程序运行的时候或者用其他方式动态绑定,以便让编译器通过编译(指定一个函数或者其他类的方法作为动态属性的setter、getter方法的运行时实现)。

其主要的作用就是用在NSManagerObject对象的属性声明上,由于此类对象的属性一般是从Core Data的属性中生成的,core data 框架会在程序运行的时候为此类属性生成getter和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 把一个字符串转换为协议等。

言归正传,我们来解释一下这里需要用到的class_addmethod 方法,这个方法有四个参数,Class 表示你要为哪个类型增加方法,SEL 参数表示你要增加的方法的选择器,IMP 表示你要添加的方法的运行时的具体实现的函数指针。其实在这里你能够看出SEL 并不能在运行时找到真正要调用的方法,IMP 才可以真正的找到实现方法的。

现在我们来正式的看以下第四个参数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 截获,但由于你没有处理,所以会报告不能识别的消息的错误。

使用场景

譬如:从网络下载一个升级包,不需要退出原有的程序,就可以动态的替换掉旧的功能等类似的需求。