iOS @property、@synthesize和@dynamic
MRC 环境下: 创建一个 Person 类, 有 name, age, gender, weight 属性:
最早的写法: 成员变量
.h 文件
@interface Person : NSObject
//成员变量, 按苹果代码规范要带下划线, 以便和 setter, getter 方法的参数区分
{
NSString *_name;
NSString *_gender;
NSInteger _age;
CGFloat _weight;
}
//声明 setter, getter 方法
- (void)setName:(NSString *)name;
- (NSString *)name;
- (void)setGender:(NSString *)gender;
- (NSString *)gender;
- (void)setAge:(NSInteger)age;
- (NSInteger)age;
- (void)setWeight:(CGFloat)weight;
- (CGFloat)weight;
@end
.m 文件
@implementation Person
//实现 setter, getter 方法
- (void)setName:(NSString *)name {
_name = name;
}
- (NSString *)name {
return _name;
}
- (void)setGender:(NSString *)gender {
_gender = gender;
}
- (NSString *)gender {
return _gender;
}
- (void)setAge:(NSInteger)age {
_age = age;
}
- (NSInteger)age {
return _age;
}
- (void)setWeight:(CGFloat)weight {
_weight = weight;
}
- (CGFloat)weight {
return _weight;
}
@end
Xcode 4.4 之前的写法: property 和 synthesize 共用
Xcode4.4版本之前: @property 和 @synthesize的功能是独立分工的
- @property的作用是: 生成成员变量 set/get 方法的声明
@property int age; 它的作用和下面两行代码的作用一致
- (void)setAge:(int)age;
- (int)age;
//注意:属性名称不要加前缀_ 否则生成的get/set方法中也会有下划线
//属性中带有下划线 _ 那么生成的get/set也会有下划线 _
//@property int _age;
//- (void)set_age:(int)_age;
//- (int)_age;
- @synthesize的作用
//@synthesize age//实现 @property 声明的 set/get 方法, 生成私有的成员变量 age(不带下划线)
生成带下划线的成员变量:
@synthesize age = _age//实现 @property 声明的 set/get 方法, 生成私有的成员变量 _age
//如果在.h文件中没有定义 _age 成员变量的话,就会在.m文件中自动生成@private类型的成员变量_age
.h 文件
@interface Person : NSObject
@property (nonatomic, assign) NSString *name;//相当于拥有了以下两个方法的声明
//- (void)setName:(NSString *)name;
//- (NSString *)name;
@property NSString *gender;//相当于拥有了以下两个方法的声明
//- (void)setGender:(NSString *)gender;
//- (NSString *)gender;
@property NSInteger age;//相当于拥有了以下两个方法的声明
//- (void)setAge:(NSInteger)age;
//- (NSInteger)age;
@property CGFloat weight;//相当于拥有了以下两个方法的声明
//- (void)setWeight:(CGFloat)weight;
//- (CGFloat)weight;
@end
.m 文件
@implementation Person
@synthesize name = _name, gender = _gender, age = _age, weight = _weight;
或分开写:
@synthesize name = _name;//相当于以下两个方法
//- (void)setName:(NSString *)name {
// _name = name;
//}
//- (NSString *)name {
// return _name;
//}
@synthesize gender = _gender;//相当于以下两个方法
//- (void)setGender:(NSString *)gender {
// _gender = gender;
//}
//- (NSString *)gender {
// return _gender;
//}
@synthesize age = _age;//相当于以下两个方法
//- (void)setAge:(NSInteger)age {
// _age = age;
//}
//- (NSInteger)age {
// return _age;
//}
@synthesize weight = _weight;//相当于以下两个方法
//- (void)setWeight:(CGFloat)weight {
// _weight = weight;
//}
//- (CGFloat)weight {
// return _weight;
//}
@end
Xcode4.4之后: @property 代替了 @synthesize的功能
@property 的作用:
- 生成了成员变量 get/set 方法的声明
- 生成了私有的带下划线的的成员变量因此子类不可以直接访问,但是可以通过get/set方法访问。那么如果想让定义的成员变量让子类直接访问那么只能在.h文件中定义成员变量了,因为它默认是@protected
- 生成了get/set方法的实现
注意:
- 当让系统自动生成setter 以及 getter 方法实现时,此时系统会自动生成实例变量
- 如果我们自己重写了setter 和 getter 方法其中之一时,系统还会自动生成实例变量
- 如果我们自己重写了setter 和 getter ,那么此时系统不再自动生成实例变量,需要我们自己创建实例变量,或者使用@sythesize来生成实例变量, 此时的实例变量是私有的
//@sythesize 在.m文件中的作用:
//(1)生成setter 和 getter 方法的实现
//(2)生成内部操作的实例变量
.h 文件
@interface Person : NSObject
@property (nonatomic, retain) NSString *name;
@property (nonatomic, copy) NSString *gender;
@property (nonatomic, assign) NSInteger age;
@property (nonatomic, assign) CGFloat weight;
@end
注意: 当使用属性时, 为了防止内存泄露, 不同语义特性 retain, copy, assign 修饰的属性, 其 setter , getter 的内部实现有所不同
注意retain, copy 修饰的属性的 setter, getter 方法的实现
#pragma mark --- 不同语义特性下的setter 和getter 的内部实现
#if 0
//assign,系统默认
//setter 方法
- (void)setName:(NSString *)name {
_name = name;
}
//getter 方法
- (NSString *)name {
return _name;
}
#endif
#if 0
//retain
//setter 方法
- (void)setName:(NSString *)name {
if (_name != name) {//避免重复操作
[_name release];//解决内存泄露问题
_name = [name retain];//解决野指针问题
}
}
//getter 方法
- (NSString *)name {
return [[_name retain] autorelease];//苹果推荐的getter方法的安全处理机制
}
#endif
#if 0
//copy
//setter 方法
- (void)setName:(NSString *)name {
if (_name != name) {
[_name release];
_name = [name copy];
}
}
//getter
- (NSString *)name {
return [[_name retain] autorelease];
}
#endif
@dynamic
@dynamic 告诉编译器:属性的 setter 与 getter 方法由用户自己实现,不自动生成。假如一个属性被声明为 @dynamic var,而且你没有提供 @setter方法和 @getter 方法,编译的时候没问题,但是当程序运行到 instance.var = someVar,由于缺 setter 方法会导致程序崩溃;或者当运行到 someVar = var 时,由于缺 getter 方法同样会导致崩溃。编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定。