总结一下工作中遇到的问题
block 是我们工作中常用的一个东西,使用它有很多注意点,我今天聊下项目上线之后使用block引发一个崩溃问题,
1.先来了解一下block捕获auto变量
我们知道block会将局部auto变量捕获到内部, 内部会强引用变量,这样会造成循环引用的问题,这是一个老生常谈的问题了,用__weak和__unsafe_unretained 都行但是后者是不安全的,只是在对象释放的时候__weak会将引用的对象置为nil,而__unsafe_unretained不会,这将会导致野指针的产生,,也就不多说了
解决办法是使用__weak弱应用他,就可以解决循环引用的问题,那么我们再来看一个现象,我开启一个子线程执行任务,我进入一个界面后,在迅速返回,并且在子线程上模拟一个耗时操作,在的耗时操作的时间内内我们返回上一层让我们的控制器销毁,我们看下会发生什么事情,结果如下
由于弱应用了self,在控制器被销毁之后,对象被释放了,所以无法保留,如果我们仍然想对对象进行操作,那就要对对象进行保活,如何进行保活我相信作为一个iOS开发者都知道的,在block内部强引用这个变量,所以是在代码块(scope)里面都不会释放,保证对象的生命周期,结果如下
本文的重点
看似很完美但是这样写代码就真的没有问题了吗?
答案是否定的,这样写只能说在block块里面任务执行完毕时没有任何问题的,如果你block里面操作了这个资源,刚好这个资源会在其他地方也有使用就会造成资源抢夺在可能,严重的会造成app崩溃影响,为了说明这个问题我来演示一下这个现象
控制器A Push控制器B,不做多余的操作
代码不变的情况下我一步操作,push完控制器我立刻pop我们的上一层控制器,也就是pop到我们的控制器A,当然我控制器A的在生命周期的方法里面移除了最后一个元素
我们看下结果
结果肯定崩溃,说明线程不安全,2个线程可以同时访问一个资源,解决资源抢夺的方案就是加锁,数据库使用databaseQueue保证线程安全访问,当然了还有种处理方案就是不要使用强引用,弱应用它就行了,一个nil发出的消息是不会被响应的,如果一定要用strongSelf来达到你项目中某些需求的话,注意block持有对象的生命周期即可,做对应的处理,
再次我要感谢bugly,如果没有buggly,我无法发现这个问题产生的原因,虽然能意思到可能是线程不安全的问题,但是却不知道是如何产生的,bugly除了可以实时的监控崩溃,还有界面跟踪功能,这个功能让我精准的定位到了意识到block延长生命周期所产生的问题,值得一提这个异常上报的埋点功能做的真的不错
当然我们在项目中写代码肯定不会怎么写,一定会判断一下是否为数组越界,项目还可以hook一些崩溃的方法,比如数组 objectAtIndex 方法减少你的项目在线上的崩溃率,对返回的消息做对应的处理,在这里我就不啰嗦了,网上有很多这样的处理方式
后记:记录这个问题希望对一些人能有所帮助