今天对项目进行了一些优化,想要把数据处理全部放在一个异步并发的队列中处理,写完代码之后发现偶尔会出现崩溃,原因就是EXC_BAD_ACCESS错误。
在网上也找到了类似的问题,有一个网易面试题:
|
|
这个其实就是我写的代码的一种直接表现的版本,其实就是::对已经释放的内存的对象再次发送消息出现的::。
原因
问题的原因是因为我们现在使用ARC编码,但是如果对于这个对象来说,它的setter方法在MRC环境下就是
|
|
而调用了问题的原因就是就是因为我们使用了异步+并发队列处理数据,也就是加入队列A执行到第二行代码,还没有执行到第三行时,队列B也执行到第二行代码,这时候队列A执行第三行代码之后就会释放对象,然后队列B使用的时候也会释放,就会造成过度释放。
解决
知道了造成问题的原因,那么解决的办法也就大概知道了。
改用串行队列
过度释放release的问题就是并发队列多次同时访问了资源,那么使用串行队列就可以解决这个问题了。主要是在setter方法中改用串行队列。
使用atomic(加锁)
我们正常初始化变量的时候一般都是使用nonatomic,也就是非原子性,而使用atomic为原子性就相当于给setter方法加锁。atomic也只是对于setter方法有用,而其他情况时需要使用其他加速方式。
使用weak
Weak关键字的setter没有保留新的值或者保留旧值的操作。所以不会引起重复释放。但是并不是所有变量都适合使用weak。
参考文档
苹果开发中文网站从一道网易面试题浅谈OC线程安全 - CocoaChina_让移动开发更简单
iOS多线程到底不安全在哪里?
我所理解的 iOS 并发编程 - 掘金
iOS多线程经典崩溃 - 简书