在开发过程中不可避免的会遇到很多需要定义属性的地方,下面就简单总结一下与属性定于有关的内容。
如何定义属性
@property (<#attributes#>) <#type#> <#name#>;
@property是用来定义属性的关键字,括号中的内容是属性的关键字,也就是属性的属性,type是属性的数据类型,name是属性的名称。
attributes
| Attributes | Attributes |
|---|---|
| atomic | nonatomic |
| strong | weak |
| readwrite | readonly |
| getter= | setter= |
| copy | assign |
| retain | unsafe_unretained |
atomic
如果没有指明是nonatomic的,那么默认就是atomic。atomic的意思是数据的读写是线程安全的,这在多线程的时候非常有用,但是与nonatomic相比的话效率会低很多。所以为了提升效率,除非是在明确知道对象会在多线程中使用,否则尽量使用nonatomic关键字。
nonatomic
nonatomic不能保证数据的原子性,也就是说在多线程访问的时候不能保证能够正确读取数据,甚至有可能发生崩溃。如果使用了nonatomic关键字,这时候如果存在多线程访问的话,需要自己来处理线程的安全问题。
strong
这是一个ARC之后才有的属性,在使用ARC的时候,这是一个默认属性。与它对应的是weak属性。strong使类能够拥有对象的所有权,也就是说,会增加对象的 retain count 以保证在类使用该对象的时候,对象没有被销毁。strong会导致“retain cycle”,要谨慎使用。
weak
只是将指针指向该对象,但是并没有对象的所有权,在对象被释放的时候,weak指针会被置为nil,这保证了指针的安全, 在OC里是可以给nil对象发送消息而不会崩溃的,但是如果给一个被释放的对象发送消息就会崩溃了。weak不会增加对象的 retain count。
copy
与strong不同的是,copy不会增加对象的 retain count,而是会重新复制一份对象,然后将指针指向新复制的对象。使用copy关键字的属性的类型必须遵循NSCopying协议。在使用同时存在 mutable 和 immutable 类型的数据时,copy是一个比较好的选择。假如有一个属性是NSString类型的,但是我们却将一个NSMutableString赋值给了它(这是合法的),如果我们使用strong关键字,那么现在这个对象是一个NSMutableString的对象,如果在别的地方修改了这个对象的值,那么该属性也跟着变了,这可能会带来意想不到的后果。但如果我们使用copy关键字的话,就不会存在这个问题了,因为它会拷贝一份NSMutableString的值,这时属性依然是
immutable 的,即使NSMutableString的对象修改了也不会影响属性的值。
copy、strong、weak以及下面要说的assign四个关键字只能使用一个,不能同时使用其中的两个或多个。
assign
简单数据类型(int,long,double, float,Bool)默认就是assign的,有点类似于下面要讲的unsafe_unretained。最好是只在简单数据类型时使用,对于对象类型,最好不要使用
retain
ARC之前使用的关键字,ARC之后用storng代替。
unsafe_unretained
ARC之前使用的关键字,类似于weak,但与weak不同的是在对象被销毁后,指针不会被置为空,所以有可能会造成崩溃
readwrite
所有的属性默认都是readwrite的,使用readonly关键字可以覆盖该默认值。
readonly
表示对象是只读的。当我们不希望外面的类可以修改该属性的时候,可以在头文件中将属性定位readonly,但是在实现文件中,我们可以将它声明为readwrite,这样就只能在类内部才能修改这个属性了。
getter= & setter=
这两个是用来给 getter 和 setter 设定一个自定义的名字。默认情况下,系统会生成一个与属性同名的getter 方法和 set<属性明> 的 setter 方法,通过getter=和setter=关键字可以指定自己想要的 getter 和 setter 名称。
@synthesis vs @dynamic
在使用属性的时候经常会用到@synthesis和@dynamic关键字,那么这两个关键字是用来干嘛的呢?
@synthesis
告诉编译器自动生成属性的 getter 和 setter 方法,并且为属性绑定一个成员变量,也就是说将属性的访问器方法作用于绑定的成员变量。正常情况下可以不使用@synthesis关键字,编译器也会默认生成访问器方法,在一些特殊情况下,需要明确使用@synthesis关键字才能生成访问器方法,包括以下情况:
- 绑定非默认的实例变量。默认情况下,系统会生成一个_
的成员变量与属性绑定在一起,如果不想使用系统生成的成员变量的话,可以通过
@synthesis name = customName来绑定一个自定义的成员变量名。 - 协议中定义的属性。当类实现的协议中包含属性时,必须在类中明确使用
@synthesis才能生成访问器方法 - 重写访问器方法。在重写 getter 和 setter 的时候需要用与属性相关的成员变量,由于重写了 getter 和 setter ,系统不会在默认合成这两个方法,也不会默认生成一个带下划线的成员变量,这时需要使用
@synthesis关键字来定一个与属性对应的成员变量。 - 类别(category)中定义的所有属性
- 重载的属性
- 重写了 setter 和 getter 或者只读属性的getter时
@dynamic
目的是告诉编译器访问器方法没有本类中实现,而是在别的地方(比如父类)中实现了,编译器就不会再发出警告了。主要是用在CoreData的NSManagedObject子类中。