前言
对于程序员而言,@property非常常见,但是@synthesize和@dynamic却很少出现,这两个关键字有什么用呢?需要怎么配合@property使用呢?本文就要讲述这个问题。
一 @property
@property用于在类、分类、协议中定义属性。所谓的属性就是语法糖,编译器在编译的时候,会将属性翻译为对应的代码。分为如下两种情况:
- 类中的属性,翻译的内容包括:_name的成员变量的声明,set和get方法的声明,set和get方法的实现。
- 分类和协议中的属性,翻译的内容包括:set和get方法的声明。
注意点1:类中的属性,编译器会自动为我们生成set和get方法,但是如果我们在某个类中同时手动实现了readwrite属性的set和get方法或着readonly属性的get方法的实现,那么编译器就会认为我们接管了自动生成成员变量、set和get方法的工作,就不会自动为我们声明成员变量、实现set和get方法了。在上述情况下,我们会看到编译器如下报错:·
@interface Student : NSObject
@property(nonatomic,assign)int age;
@end
@implementation Student
- (void)setAge:(int)age {
_age = age;
}
- (int)age{
return _age;
}
@end
编译器提示,没有声明_age。此时,@property的功能只能生成set和get的声明,并不能生成实例变量和set和get的实现。在这种情况下,只能我们自己手动声明实例变量了,有两种方式:
1.自己声明一个实例变量:
@interface Student : NSObject
{
int _age;
}
@property(nonatomic,assign)int age;
@end
2.利用@synthesize(这一点可以先略过不看,等看完第二部分关于@synthesize的介绍再回头看这里就会明白是咋回事了):
@synthesize age = my_age;
这个问题的官方文档描述如图所示:
注意点2:定义在分类和协议中的@property,编译器仅会为我们生成set和get的声明,不会为我们生成实例变量和get和set方法的实现:
- 分类中的@property需要我们手动实现set和get方法,且其中不能定义成员变量,可以用关联对象的形式变相定义"成员变量"。
- 协议中的@property,某个类遵守了这个协议,那么这个类就需要手动实现set和get方法以及定义成员变量,或者使用@synthesize让编译器自动合成。
二 @synthesize
@synthesize只能出现在类的@implementation中,格式是@synthesize 属性名 = 实例变量名,其中实例变量名可以省略,那么生成的实例变量名将和属性名保持一致,如下代码所示:
@synthesize age;
@synthesize name = my_name;
等同于如下代码:
@synthesize age = age;
@synthesize name = my_name;
@synthesize有什么用呢?@synthesize的第一个参数必须是已经定义的属性名,也就是说,它只能用于已经定义的@property,它会为属性声明指定名字的成员变量,为属性生成get和set方法的实现。到这里我们不禁困惑,类中的@property不是已经做了这些工作了吗,@synthesize存在的意义是是什么?Apple为什么要这么设计呢?其实这是有历史原因的:
- xcode4.4之前,@property只负责set方法和get方法的声明,并不负责实例变量的定义、set和get方法的实现。需要通过@synthesize来定义实例变量和生成set和get方法的实现,所以在那时候,@property和@synthesize通常成对出现。
- xcode4.4之后,@property功能变得更加强大,负责set方法和get方法的声明和实现、实例变量的定义。而@synthesize功能不变。所以@property包含了@synthesize的功能,使用场景变多,而@synthesize用的场景减少。
所以,@synthesize的使用场景非常少,但是它也还是有价值的,所以Apple也没有将这个关键字删除。场景如下:
- 在property功能健全的时候(类中的property,且程序员没有同时自定义readwrite property的set和get的实现、readonly property的set和get实现),@synthesize的作用是更改实例变量的名字,默认是_name,可以更改为我们指定的名字;
- 在property功能不健全的时候(协议中定义的property,或类中的property程序员同时自定义readwrite property的set和get的实现、readonly property的set和get实现),编译器只生成了get和set的声明,@synthesize的作用定义实例变量,生成set和get的实现。
三 @dynamic
@dynamic比较简单,它也需要配合属性使用:
@implementation Student
@dynamic age;
@end
@dynamic的作用是告诉编译器,不必为我们生成set和get方法的实现以及实例变量,我们要手动实现。
结束语
至此,@property和@synthesize、@dynamic的配合使用就介绍完了。@synthesize、@dynamic是@property在某些场景下的辅助和补充。
参考官方文档:objc-apple