声明属性时,在ARC环境下会经常用到几个关键字nonatomic
、 atomic
、readonly
、readwrite
、 strong
、copy
、assign
、weak
等,使用过程中并不是很得心应手,因此做个总结。
非ARC环境下的retain
、 release
就不在这里赘述了。
属性的参数应该按照下面的顺序排列: 原子性,读写 和 内存管理。 这样做你的属性更容易修改正确,并且更好阅读。(译者注:习惯上修改某个属性的修饰符时,一般从属性名从右向左搜索需要修动的修饰符。最可能从最右边开始修改这些属性的修饰符,根据经验这些修饰符被修改的可能性从高到低应为:内存管理 > 读写权限 >原子操作)
引用自《禅与 Objective-C 编程艺术》
原子操作
-
nonatomic
:非原子性访问,对属性赋值的时候不加锁,多线程并发访问会提高性能。如果不加此属性,则默认是两个访问方法都为原子性访问; -
atomic
:置成员变量的@property属性时,默认为atomic
,提供多线程安全,在多线程环境下,原子操作是必要的,否则有可能引起错误的结果。
atomic的意思就是
setter/getter
这个函数,是一个原语操作。如果有多个线程同时调用setter
的话,不会出现某一个线程执行完setter
全部语句之前,另一个线程开始执行setter
情况,相当于函数头尾加了锁一样,可以保证数据的完整性。nonatomic
不保证setter/getter
的原语性,所以你可能会取到不完整的东西。因此,在多线程的环境下原子操作是非常必要的,否则有可能会引起错误的结果。比如
setter
函数里面改变两个成员变量,如果你用nonatomic
的话,getter
可能会取到只更改了其中一个变量时候的状态,这样取到的东西会有问题,就是不完整的。当然如果不需要多线程支持的话,用nonatomic
就够了,因为不涉及到线程锁的操作,所以它执行率相对快些。在默认情况下,由编译器所合成的方法会通过锁定机制确保其原子性(atomicity)。如果属性具备
nonatomic
特质,则不使用同步锁。请注意,尽管没有名为“atomic”
的特质(如果某属性不具备nonatomic
特质,那它就是“原子的”(atomic
)。
在iOS开发中,几乎所有属性都声明为
nonatomic
。
一般情况下并不要求属性必须是“原子的”,因为这并不能保证“线程安全” ( thread safety),若要实现“线程安全”的操作,还需采用更为深层的锁定机制才行。例如,一个线程在连续多次读取某属性值的过程中有别的线程在同时改写该值,那么即便将属性声明为atomic
,也还是会读到不同的属性值。因此,开发iOS程序时一般都会使用
nonatomic
属性。但是在开发 Mac OS X 程序时,使用atomic
属性通常都不会有性能瓶颈。
读写
-
readwrite
:同时产生setter\getter方法
此标记说明属性会被当成读写的,这也是默认属性。设置器和读取器都需要在@implementation中实现。如果使用@synthesize关键字,读取器和设置器都会被解析。
-
readonly
:只产生简单的getter,没有setter。
此标记说明属性是只读的,默认的标记是读写,如果你指定了只读,在@implementation中只需要一个读取器。或者如果你使用@synthesize关键字,也是有读取器方法被解析。而且如果你试图使用点操作符为属性赋值,你将得到一个编译错误。
内存管理
-
strong
:在ARC环境下等同于retain
,声明属性的默认关键字。(浅拷贝,拷贝指针) -
copy
:深拷贝,拷贝内容,copy
就是复制一个不可变 Object 的对象
Example:
//.h文件
@property (nonatomic, copy) NSMutableArray mutableArray;
//.m文件
NSMutableArray *array = [NSMutableArray arrayWithObjects:@1,@2,nil];
self.mutableArray = array;
[self.mutableArray removeObjectAtIndex:0];
上述代码,如果成员变量 mutableArray
使用 copy
,在 self.mutableArray = array;
执行后,self.mutableArray
只是拷贝了array
的内容,并没有拷贝array
的指针,所有self.mutableArray
实际不可变,所以无法执行removeObjectAtIndex:
操作;
补充说明:self.mutableArray
拷贝了array
的内容,在拷贝过程中其实只是拿到了array
的所有object的指针,也就是浅拷贝了array
的所有object。
Example:
//.h文件
@property (nonatomic, copy) NSMutableArray mutableArray;
//.m文件
NSMutableString *string = [[NSMutableString alloc]initWithString:@"123456"];
NSMutableArray *array = [[NSMutableArray alloc]initWithObjects:string, nil];
self.mutableArray = array;
[string deleteCharactersInRange:NSMakeRange(1, 1)];
NSLog(@"%@",self.mutableArray);
上述代码,最后打印结果为:
2017-06-05 00:08:39.190 YYProject[88423:1877006] (
13456
)
-
assign
:基础数据类型(NSInteger,CGFloat)和C数据类型(int, float, double, char等)使用 -
weak
:对象销毁之后会自动置为nil,防止野指针。
Delegate基本总是使用weak,以防止循环引用。特殊情况是,希望在dealloc中调用delegate的某些方法进行释放,此时如果使用weak将引起异常,因为此时已经是nil了,那么采用assign更为合适,这时需要自己手动在dealloc中给Delegate置为nil。
iOS开发——OC篇&常用关键字的使用与区别 - iCocos - 博客园
网友评论