1、@property有两个对应的词,一个是@synthesize,一个是@dynamic。如果@synthesize和@dynamic都没写,那么默认的就是@syntheszie var = _var;
2、@synthesize的语义是如果你没有手动实现setter方法和getter方法,那么编译器会自动为你加上这两个方法。
3、@dynamic告诉编译器,属性的setter与getter方法由用户自己实现,不自动生成。(当然对于readonly的属性只需提供getter即可)。假如一个属性被声明为@dynamic var,然后你没有提供@setter方法和@getter方法,编译的时候没问题,但是当程序运行到instance.var =someVar,由于缺setter方法会导致程序崩溃;或者当运行到 someVar = var时,由于缺getter方法同样会导致崩溃。编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定。
@dynamic 使用后而且没有自己实现
-[Car name]: unrecognized selector sent to instance 0x6000000109e0
@dynamic 就是要来告诉编译器,代码中用@dynamic修饰的属性,其getter和setter方法会在程序运行的时候或者用其他方式动态绑定,以便让编译器通过编译。其主要的作用就是用在NSManageObject对象的属性声明上,由于此类对象的属性一般是从Core Data的属性中生成的,Core Data框架会在程序运行的时候为此类属性生成getter和Setter方法。
1.@synthesize 该关键字没什么好说的,无非就是自动生成,而且现在都不用手动加,默认就是自动生成的
2.@dynamic 该关键字就是告诉编译器,该属性不需要系统帮忙自动生成,关键来了,当你一个继承NSObject的对象,弄了一个属性,显然父类是没有一样的属性的,这种情形下,你需要手动生成getter和setter,如果没有生成,编译阶段没问题,而你访问的时候就会找不到方法而崩溃。
还有一种情形就是父类有个属性,已经默认自动生成了,而子类也声明了同样的属性,你如果也默认,不做其他操作,这种情形下,子类的属性就会出现警告,由于属性是继承来的,默认是在父类实现getter和setter,子类警告不会在子类出现getter和setter,会去其父类查找,那么你子类声明dynamic
,也就是告诉他我会手动生成或者我父类有,你别警告我了,你运行起来就能找到了,自然,警告消除,运行起来调用就会去调用父类的getter和setter,能找到,就不会崩溃
关键词的场景,之前@dynamic只在NSManagedObject的子类中遇到过,因为NSManagedObject的子类是由CoreData直接生成的,其中对应参数(@property)的setter和getter方法也是由CoreData直接生成,并且不展现给你
首先介绍一下什么是setter和getter方法:
由名字也大致能猜出
getter方法是当你的程序某处读取一个参数A的时候,会调用的方法,它会返回当前A的值
setter方法是当你的程序某处给参数A赋值的时候,会调用的方法,把新值赋值给变量A
接下来,我们看一个非常老的标准的setter && getter方法
@interface Sample()
@property(nonatomic, strong, readwrite)NSObject *sampleObject;
@end
@implementation Sample
@synthesize sampleObject = _sampleObject;
//getter
- (NSObject *)sampleObject
{
return _sampleObject;
}
//setter
- (void)setSampleObject:(NSObject *)sampleObject
{
_sampleObject = sampleObject;
}
@end
synthesize中文意思为‘合成’,在编译的过程中,编译器会帮你自动生成getter和setter方法,也就是说,上述代码中,把
- (NSObject *)sampleObject
- (void)setSampleObject:(NSObject *)sampleObject
两个函数的实现删除掉也是没有关系的。因为@synthesize语法糖会让编译器帮助你生成getter和setter方法
以上都是老的写法,但是现在看来基本上都是自动默认的,即使你不写@synthesize,它同样会自动帮你生成getter和setter方法
于是就到了今天主要要讲的@dynamic
关键词。之前也说到了,这个关键词用的不多,最常见的地方还是在CoreData的NSManagedObject
中会看见。
@dynamic
A相当于告诉编译器:“参数A的getter和setter方法并不在此处,而在其他地方实现了或者生成了,当你程序运行的时候你就知道了,所以别警告我了,如下警告示例”这样程序在运行的时候,对应参数的getter和setter方法就会在其他地方去寻找,比如父类
Auto property synthesis will not synthesize property ‘viewModel’; it will be implemented by its superclass, use @dynamic to acknowledge intention
父类
@interface father()
@property (nonatomic, strong, readwrite) NSObject *sampleObject;
...
@synthesize sampleObject = _sampleObject;
@end
子类
@interface child : father
@property (nonatomic, strong, readwrite) NSObject *sampleObject;
...
@dynamic sampleObject;
@end
这样的话,如果你在子类中调用sampleObject,则会调用父类的getter方法。
比如类遵守一个delegate时,delegate中的参数在父类的初始化方法中就赋值了,而子类的没有自己的初始化方法的时候,子类中的此参数就可以设为@dynamic,即和父类共用一个参数
基类控制器.h和.m部分代码
@interface MKJBaseViewController : UIViewController
@property (nonatomic, strong, readonly) MKJBaseViewModel *viewModel;
@end
@interface MKJBaseViewController ()
@property (nonatomic, strong) MKJBaseViewModel *viewModel;
@end
@implementation MKJBaseViewController
- (instancetype)initWithViewModel:(MKJBaseViewModel *)viewModel{
self = [super initWithNibName:nil bundle:nil];
if (self) {
_viewModel = viewModel;
}
return self;
}
子类.h,.m文件部分代码
@interface MKJMainViewController : MKJBaseViewController
@property (nonatomic,strong,readonly) MKJMainViewModel *viewModel;
@end
@interface MKJMainViewController ()
@end
@implementation MKJMainViewController
@dynamic viewModel;
上面部分代码可以看出,子类已经有一个ViewModel用来初始化,每次初始化的viewModel实例都是根据具体控制器的业务逻辑进行初始化,你如果直接访问self.viewModel
,而且直接访问MKJMainViewModel
中的方法,肯定是不行的,除非你这么做(MKJMainViewModel *)self.viewModel
,这样做就麻烦点了,其实可以用到上面的关键字dynamic
在子类里面生成一个属性,属性名字和父类一样,这样就会出现上面的警告,告诉我们不会自动生成,由于是继承来的,他会在父类生成实现,那么为了消除警告,你可以在m文件中的实现下面加上@dynamic viewModel;
,也就是这个关键字的作用,告诉编译器,不要警告了,getter和setter并不在此处,你运行的时候就知道从父类找了,那么当你子类调用self.viewModel
的时候,你拿到的就是从基类的getter方法中拿出的实例对象
参考博文