详解 property
在利用 Objective-C 的开发中,我们需要创建许多的类,类包括成员变量和成员方法/类方法 (Objective-C 中没有类成员变量)。但是大部分 Obj-C 的类文件中都看不到成员变量的申明,我们更多看到的是形如: @property (nonatomic, copy) NSString *name;
。这是因为当我们这样写之后,Xcode 会自动为我们添加成员变量,并生成相应成员变量的存取方法。
- 手动编写成员变量/存取方法
@interface XYDog: NSObject {
NSString *_name;
}
- (void)setName:(NSString *)name;
- (NSString *)name;
@end
@implementation XYDog
- (void)setName:(NSString *)name {
_name = [name copy];
}
- (NSString *)name {
return _name;
}
@end
- Xcode 自动生成
@interface XYDog: NSObject
@property (nonatomic, copy) NSString *name;
@end
@implementation XYDog
@end
仅通过 @property,Xcode 就自动生成手动编写的代码,这大大提高了开发效率。
@property 之后的关键字
-
原子性:默认情况下,编译器合成的方法会通过锁定机制保证原子性
- atomic:加锁,使用同步锁的开销较大,iOS 开发一般情况下不会用此关键字,Mac OS X 开发使用该关键字不会有性能瓶颈。
- nonatomic:不加锁。
-
读/写权限:
- readwrite:同时具有
getter
和setter
。 - readonly:只有
getter
。
- readwrite:同时具有
-
内存管理:
- assign:只针对 「储量类型」 的简单赋值操作 (int/double/CGFloat/CGRect)。
- strong:为这种属性设置新值时,setter 会 retain 新值,release 旧值,再将新值设置给实例变量。
- weak:为这种属性设置新值时,setter 不会 retain 新值,也不会 release 旧值,当引用的对象被释放时,该属性会被自动设为 nil。
- unsafe_unretained:与 assign 相同,适用于对象类型,不会 retain 引用的对象,引用的对象被销毁后,不会被自动设为 nil。
- copy:为这种属性设置新值时,不会 retain 新值,而会将其拷贝一份,在设置给实例变量。当属性类型为
NSString *
时,经常用这个关键字。
-
方法名:
- getter=
指定获取方法名, @property (nonatomic, assgin, getter=isOn) BOOL on;
- setter=
指定设置方法名。
- getter=
自己申明成员变量
这是不是意味我们就不需要再关心成员变量的创建了?并不是。Xcode 在某些情况下,不会生成成员变量:
- 重写了 readonly 属性的 getter
- 重写了 readwrite 属性的 setter 和 getter
- 在 .m 文件中用 @dynamic 标记的属性
在这些情况下,Xcode 会认为我们自己要管理成员变量,所以就不会合成成员变量。
在这几种情况下,假如我们需要成员变量的话,就得自己申明成员变量,这里有两种方法:
- 第一种
@interface XYDog: NSObject
@property (nonatomic, readonly) NSString *name;
@end
@implementation XYDog {
NSString *_name;
}
- (NSString *)name {
if (![_name isEqualToString:@"yys"]) {
return @"lzh";
}
return _name;
}
@end
- 第二种
@interface XYDog: NSObject
@property (nonatomic, readonly) NSString *name;
@end
@implementation XYDog
@synthesize name = _name;
- (NSString *)name {
if (![_name isEqualToString:@"yys"]) {
return @"lzh";
}
return _name;
}
@end
这种方法还是告诉 Xcode 帮我们合成成员变量。
注意事项
我们访问成员变量的通常用的是形如 dog.name
的点语法,这不是 Objective-C 语言的特性,而是 Xcode 特性,Xcode 会把这样的语法翻译成调用 setter 或者 getter,因此我们能获得或者设置成员变量的值。
直接访问成员变量的语法是 dog->name
,Objective-C 对象本质上是 C 语言的结构体,所有这里就是访问结构体的成员变量。同样在 .m 文件中用 _name
访问同样也是直接访问成员变量。
我们在 .m 文件中重写 setter 和 getter 方法时,有几点需要注意:
- 不要在 getter 中使用形如
self.name
的语句来访问成员变量,Xcode 会将这个翻译成 getter 方法的调用,这里就会造成死循环。 - 同样不要在 setter 中使用形如
self.name = @"Jerry";
的语句来设置成员变量的值,原因同上。 - 我们应该使用
_name
或者_name = @"xxx;"
来访问和设置成员变量的值。