Apple的官方文档中, @synthesize主要有两个使用场景:
1.给属性对应的实例变量重命名. 看代码:
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
- (instancetype)initWithName:(NSString *)name;
@end
定义了一个属性name, 编译器会默认生成一个与name对应的实例变量, 名称是在属性名前面加下划线, 即_name. 我们可以在类内部直接使用这个实例变量:
@implementation Person
- (instancetype)initWithName:(NSString *)name {
if (self = [super init]) {
_name = [name copy]; // 在初始化方法中直接使用_name
}
return self;
}
@end
事实上, 上面的代码中还有一句隐含的代码, 在@implementation Person这一行下面, 有@synthesize name = _name; 这一句是编译器默认添加的, 作用就是把name属性对应的实例变量命名为 _name:
@implementation Person
@synthesize name = _name; // 这一句为编译器默认添加, 不需要自己写出来
- (instancetype)initWithName...
@end
如果你不喜欢_name这个实例变量名, 或者有其他原因不能使用 _name这个名字, 你可以用@synthesize来给name属性对应的实例变量指定一个其它的名字, 比如:
@implementation Person
@synthesize name = ivarName; // 指定实例变量的名字为ivarName
- (instancetype)initWithName:(NSString *)name {
if (self = [super init]) {
ivarName = [name copy]; // 在初始化方法中使用指定的实例变量名
}
return self;
}
@end
此时, ivarName就和默认的_name作用一样了. 另外, 如果你只写了@synthesize name; 没有指定新的名字, 那么对应实例变量的名字就会和属性名一样, 都叫做name了:
@implementation Person
@synthesize name; // 不指定新名字, 那么实例变量的名字也叫做name
// 这里必须给方法的参数换个名字, 否则原来的参数名也叫name, 在方法内部会把实例变量name覆盖掉
- (instancetype)initWithName:(NSString *)aName {
if (self = [super init]) {
name = [aName copy];
}
return self;
}
@end
2.如果你自己同时实现了一个属性的getter和setter, 或者一个只读属性的getter, 那么编译器就不会自动为我们生成属性对应的实例变量了. 此时, 我们可以使用@synthesize来手动创建该属性的实例变量:
@implementation Person
@synthesize name = _name; // 同时实现getter和setter, 则需要手动创建属性对应的实例变量, 名字可以任意取
- (instancetype)initWithName:(NSString *)name {
if (self = [super init]) {
_name = [name copy];
}
return self;
}
#pragma mark - getter & setter -
- (NSString *)name {
return _name;
}
- (void)setName:(NSString *)name {
_name = [name copy];
}
@end
@dynamic的作用: 告诉编译器, 不要自动实现属性的getter和setter方法, 而要由我们手动去实现. 此时, 编译器也不会自动为我们生成属性对应的实例变量, 需要我们自己去处理. 而且要注意的是, 不能像上面的例子那样用@synthesize来手动创建该属性的实例变量, 因为实验表明, @dynamic和@synthesize是不能共存的. 那怎么办呢? 其实也简单, 我们可以在.m文件中增加一个实例变量, 让它来扮演属性对应的实例变量:
@implementation Person {
NSString *_name; // 增加一个实例变量, 跟name属性对应起来
}
@dynamic name; // 使用了@dynamic, 此时必须手动实现getter和setter
- (instancetype)initWithName:(NSString *)name {
if (self = [super init]) {
_name = [name copy];
}
return self;
}
#pragma mark - getter & setter -
- (NSString *)name {
return _name;
}
- (void)setName:(NSString *)name {
_name = [name copy];
}
@end
最后注意, 如果你使用了@dynamic, 却没有实现该属性的getter和setter, 那么在其它地方调用该属性的getter或setter时, 程序就会崩溃.