熟悉OC的小伙伴都会经常用到property
(属性),属性是OC语言的一种特性,主要作用是封装对象中的数据,OC对象通常会把所需要的数据保存为各种实例变量。实例变量一般通过存取方法(access method)来访问。
使用属性时又一个问题需要注意:就是属性后面会经常附带一些特质
(attribute),区分好每一种特质的作用是非常必要的。
例如下面的代码就有三种特质:
@property (nonatomic, copy, readonly) NSString * aString;
属性的特质主要分为以下四类:
1.原子性
在默认情况下,由编译器所合成的方法会通过锁定机制确保其原子性(atomicity)。如果属性具备nonatomic
特质,则不需要使用同步锁。与nonatomic
对应的是atomic
。注意:尽管没有命名为atomic
的特质,扔可以在属性的特质中写atomic
的声明,编译器也不会报错。若是自己定义属性的存取方法,就应该遵循属性的特质。
具备atomic
特质的属性的获取方法会通过锁定机制来确保其操作的原子性。也就是说,如果有两个线程读写同一个属性,那么不论何时都能有效的属性值。如果时nonatomic
特质(不加锁)的属性,当其中一个线程在改写值时,另一个线程也会突然闯入,把尚未修改好的属性值读取出来,这种情况下读取出来的值有可能是错误的。但是atomic
特质会对系统能耗较大,属性常用nonatomic
,也是默认的特质。
2.读/写权限
- 读&写:具备readwrite特质的属性拥有
获取方法(getter)
和设置方法(setter)
,如果属性由@synthesize实现,则编译器会自动生成这两个方法(虽然再Xcode中看不见,但是可以直接使用) - 只读:具备readonly特质的属性将只拥有
获取方法(getter)
,只有在属性由@synthesize实现时,编译器才会为其合成获取方法。
3.内存管理
属性用于封装数据,而数据需要有具体的所有权语义(concrete ownership semantic)
,下面这些会影响属性的设置方法(setter)
。
assign
设置方法
只会执行针对`纯量类型·(比如:NSInteger,CGFloat,int等)的操作。strong 此特性表明了属性定义了一种
拥有关系(owning relationship)
。为这种属性设置新的值时,设置方法会先保留新值,并释放旧值,然后再将新值赋值上去。
- (void)setName:(NSString *)newName {
NSString *tmp = newName;
[_oldName release];
_oldName = tmp;
}
weak 此特质表明了属性定义了一种
非拥有关系(nonowning relationship)
。为这种属性设置新值时,设置方法既不保留新值也不释放旧值。此特质与assign
类似,然而在属性所对应的对象被释放时,属性的值会设置为nil
。unsafe_unretaind 此特质的定义与
assign
特质相同,不同的是它适用于对象类型(object type)
,该特质表明了一种不保留关系(unretained)
,当所指对象被释放时,属性不会自动设置为nil
(不安全 unsafe),这一点与weak
区分。copy 此特质所表达的所属关系与
strong
类似,不同的是其设置方法
不会保留新值,而是将新值拷贝(copy)。属性类型是NSString
时经常用此特质来保护其封装性,因为传递给设置方法的新值可能指向一个NSMutableString
类的实例,此时如果不拷贝字符串,那么设置完属性之后,字符串的值可能在对象不知情的情况下被人修改。所以此时需要拷贝(copy)
一份不可变的字符串,确保对象中的值不会不经意间变动。只要实现属性所用的对象是可变的
,就应该在设置新值时拷贝(copy)
一份。
4.方法名
可通过如下特质来制定获取方法
、设置方法
的名称。
- getter=<name> 此特质用来指定
获取方法
的名称。如果属性时BOOL
值,而你想为其获取方法加上is
前缀,就可以用这个特质来指定,编译器就会为你合成获取方法
。
@prpperty (getter=isAuth) BOOL auth;
- setter=<name> 此特质涌来指定
设置方法
的名称,用的不常见。
over。
参考
《Effective Objective-C》