@property修饰符种类
当我们定义一个字符串属性时,通常我们会这样写:
@property (nonatomic, copy) NSString *name;
复制代码
当我们定义一个NSMutableArray类型的属性时,通常我们会这样写:
@property (nonatomic, strong) NSMutableArray *books;
复制代码
而当我们定一个基本数据类型时,会这样写:
@property (nonatomic, assign) int age;
复制代码
定义一个属性时,nonatomic、copy、strong、assign等被称作是关键字,或者是修饰符。
修饰符种类
修饰符有四种:
- 原子性。原子性有nonatomic、atomic两个值,如果不写nonatomic,那么默认是atomic的。如果属性是atomic的,那么在访问其getter和setter方法之前,会有一些判断,大概是判断是否可以访问等,这里系统使用的是自旋锁。由于使用atomic并不能绝对保证线程安全,且会耗费一些性能,因此通常情况下都使用nonatomic。
- 读写权限。读写权限有两个取值,readwrite和readonly。声明属性时,如果不指定读写权限,那么默认是readwrite的。如果某个属性不想让其他人来写,那么可以设置成readonly。
- 内存管理。内存管理的取值有assign、strong、weak、copy、unsafe_unretained。
- set、get方法名。如果不想使用自动合成所生成的setter、getter方法,声明属性时甚至可以指定方法名。比如指定getter方法名:
@property (nonatomic, assign, getter=isPass) BOOL pass;
复制代码
属性pass的getter方法就是
- (BOOL)isPass;
复制代码
默认修饰符
声明属性时,如果不显示指定修饰符,那么默认的修饰符是哪些呢?或者说未指定的修饰符,默认取值是什么呢?
如果是基本数据类型,默认取值是:atomic,readwrite,assign
如果是Objective-C对象,默认取值是:atomic,readwrite,strong
atomic是否是线程安全的
上面提到了,声明属性时,通常使用nonatomic修饰符,原因就是因为atomic并不能保证绝对的线程安全。举例来说:
单独的原子操作绝对是线程安全的,但是组合一起的操作就不能保证。
1 - (void)competition { 2 self.intSource = 0; 3 4 dispatch_async(queue1, ^{ 5 for (int i = 0; i < 10000; i++) { 6 self.intSource = self.intSource + 1; 7 } 8 }); 9 10 dispatch_async(queue2, ^{ 11 for (int i = 0; i < 10000; i++) { 12 self.intSource = self.intSource + 1; 13 } 14 }); 15 }
最终得到的结果肯定小于20000。当获取值的时候都是原子线程安全操作,比如两个线程依序获取了当前值 0,于是分别增量后变为了 1,所以两个队列依序写入值都是 1,所以不是线程安全的。
所以 atomic通过这种方法,在运行时保证 set,get方法的原子性。仅仅是保证了set,get方法的原子性。
但是self.intA = self.intA + 1这个表达式并不是原子操作。所以线程是不安全的。所以仅仅使用atomic并不能保证线程安全。
解决的办法应该是增加颗粒度,将读写两个操作合并为一个原子操作,从而解决写入过期数据的问题。
1 objcos_unfair_lock_t unfairLock; 2 - (void)competition { 3 self.intSource = 0; 4 5 unfairLock = &(OS_UNFAIR_LOCK_INIT); 6 dispatch_async(queue1, ^{ 7 for (int i = 0; i < 10000; i++) { 8 os_unfair_lock_lock(unfairLock); 9 self.intSource = self.intSource + 1; 10 os_unfair_lock_unlock(unfairLock); 11 } 12 }); 13 14 dispatch_async(queue2, ^{ 15 for (int i = 0; i < 10000; i++) { 16 os_unfair_lock_lock(unfairLock); 17 self.intSource = self.intSource + 1; 18 os_unfair_lock_unlock(unfairLock); 19 } 20 }); 21 }
在接下来的文章里会分别去讲解用法