iOS开发面试整理之小知识篇(二)
-
atomic和nonatomic区别
@property(nonatomic, retain) UITextField *userName; @property(atomic, retain) UITextField *userName; @property(retain) UITextField *userName;
- atomic与nonatomicd的主要区别就是系统自动生成的getter/setter方法不一样
- atomic系统自动生成的getter/setter方法会进行加锁操作
- nonatomic系统自动生成的getter/setter方法不会进行加锁操作
- atomic
- 系统生成的getter/setter方法会进行加锁操作,注意:这个锁仅仅保证了getter和setter存取方法的线程安全.
- 因为getter/setter方法有加锁的缘故,故在别的线程来读写这个属性之前,会先执行完当前操作.
- 例如: 线程1调用了某一属性的setter方法并进行到了一半,线程2调用其getter方法,那么会执行完setter操作后,在执行getter操作,线程2会获取到线程1 setter后的完整的值.
- 当几个线程同时调用同一属性的setter、getter方法时,会get到一个完整的值,但get到的值不可控.
- 例如: 线程1 调用getter 线程2 调用setter 线程3 调用setter 这3个线程并行同时开始,线程1会get到一个值,但是这个值不可控,可能是线程2,线程3 set之前的原始值,可能是线程2 set的值,也可能是线程3 set的值
- 当一个线程正在get或set时,又有另一个线程同时在进行成员变量的release操作,可能会直接crash
- 假设有一个 atomic 的属性 “name”,如果线程 A 调
[self setName:@"A"]
,线程 B 调[self setName:@"B"]
,线程 C 调[self name]
,那么所有这些不同线程上的操作都将依次顺序执行——也就是说,如果一个线程正在执行getter/setter
,其他线程就得等待。因此,属性 name 是读/写安全的。 - 但是,如果有另一个线程 D 同时在调
[self.name release]
,那可能就会crash,因为 release 不受 getter/setter 操作的限制。简单来说就是,通过get、set来访问成员变量_name是安全的,但是拿到成员变量之后,即self.name
,然后通过多线程对这个成员变量进行其他的操作,比如release,那么set、get方法就有可能崩溃 - 也就是说,这个atomic只能说是读/写安全的,但并不是线程安全的,因为别的线程还能进行读写之外的其他操作。线程安全需要开发者自己来保证。
- 假设有一个 atomic 的属性 “name”,如果线程 A 调
- atomic、nonatomic的特点:
- atomic
- 是默认的
- 会保证CPU能在别的线程来访问这个属性之前,先执行完当前流程
- 在getter和setter内部加了线程同步的锁,通过查看objc4的objc-accessors.mm的源码,用的是自旋锁spinlock_t
- 速度不快,耗性能,因为要保证操作整体完成
- iOS开发大部分情况不会出现多条线程同时调用get、set方法
- 它并不能保证使用属性的过程是线程安全的
- nonatomic
- 不是默认的
- 更快
- 线程不安全,如有两个线程访问同一个属性,会出现无法预料的结果
- atomic
- atomic与nonatomicd的主要区别就是系统自动生成的getter/setter方法不一样