在OC中,声明一个属性我们常会用到nonatomic(非原子)或者atomic(原子)来修饰属性.加上这种修饰会影响系统编译时生成的setter/getter方法,如果setter/getter方法为自己重写的,那这种修饰将不起作用.
nonatomic修饰的属性生成的setter/getter方法
//@property(nonatomic, retain) UITextField *userName;
//系统生成的代码如下:
- (UITextField *) userName {
return _userName;
}
- (void) setUserName:(UITextField *)userName_ {
[_userName retain];
[_userName release];
_userName = userName;
}
atomic修饰的属性生成的setter/getter方法
//@property(retain) UITextField *userName;
//系统生成的代码如下:
- (UITextField *) userName {
UITextField *retval = nil;
@synchronized(self) {
retval = [[userName retain] autorelease];
}
return retval;
}
- (void) setUserName:(UITextField *)userName_ {
@synchronized(self) {
[_userName release];
_userName = [userName retain];
}
}
synchronized是自旋锁,如果发现有其它线程正在锁定代码,线程会用死循环的方式,一直等待锁定的代码执行完成。
从上面代码中可以看到, atomic系统自动生成的getter/setter方法会进行加锁操作,而nonatomic系统自动生成的getter/setter方法不会进行加锁操作.
也就是a线程执行get方法过程中,b/c执行set方法时,如果是nonatomic修饰,那么无法确定a得到的值,可能是原始值,也可能是b/c设置的值,甚至抛出异常;如果是atomic修饰,只有等a线程执行完get方法,b/c线程才能依次执行.
atomic并不是绝对的线程安全,它只是对setter/getter方法做了自旋锁,只能让读写安全.譬如在a线程执行set方法时,b线程执行release,就有可能在set时自已已经被释放掉了,因为别的线程还能进行读写之外的其他操作.
总结
atomic(原子属性)保证了getter和setter存取方法的线程安全,但并不能保证整个对象的线程安全.
nonatomic(非原子属性)没有线程安全,但响应迅速耗费资源少,如果没有多线程之间的通讯,使用nonatomic是更好的选择.
网友评论