IOS中ARC模式下的crash之僵尸对象

来源:互联网 发布:国家税务网络大学 编辑:程序博客网 时间:2024/05/19 16:29

一、问题

我们先来看下crash的实例场景:



控制台中,会显示"message sent to dealloccated instance"的信息,意思就是使用一个已经释放的对象。这个释放的对象,其实跟nil对象是不同,它不是nil,只是对象的内存被释放了。ios中,向一个nil对象发送消息,是不会crash的,应该是ios底层做了容错处理。说到这里,想起来C/C++中,内存的释放过程,比如

一般都需要在释放后,把指针置为NULL。但IOS中,非ARC模式下,assign修饰的对象不会被置为nil。



二、解决

在非arc下,对象的管理由开发者控制,retain、release等对引用计数的操作需要配对,如果产生了对象释放的错误以致crash问题,那就是开发者的问题,好好检查代码即可解决;但是arc模式下,对象的管理都交给ios自己去做,那我们开发者怎么去避免上述的问题呢?


ARC模式下,容易产生上述问题的场景主要有两个:一是方法内的局部对象,在其他方法使用; 二是异步过程的回调,比如网络操作。


(1) 局部对象

在其中一个方法内alloc的一个对象,出了该方法域,就会被释放,再到其他方法使用自然就不对。典型的应用就是视频播放:


只要MPMoviePlayerController *player;(局部),修改为全局或者属性或者项目修改为非ARC即可。


(2) 网络请求

网络请求一般都是异步的,有结果后然后回调。当网络有结果后,接收回调的对象可能已经释放,那么程序就会crash,参见最前面的贴图。

如果一个对象有判断是否被销毁的属性,或者判断引用计数是否为0,那就好办了。在非ARC下,有个retainCount属性可以获取对象的引用计数,但是arc下无法使用。更不幸的,即使有这些属性,但是对象都已经被销毁了,根本无法获取他们。

但是Apple还是考虑到了这些问题,它的官方文档,有如下说明:

所以,我们需要通过dealloc做一些事情。大家都知道ARC后是不能显示地调用dealloc方法,但是可以重载此方法,且重写子类dealloc时不能调用[super dealloc]。(arc下,虽然没有显式调用父类的[super dealloc],但结果仍然会调用,应该是编译期间编译器会聪明的帮我们加上了[super dealloc]。)

我们重载对象的dealloc方法,然后把里面的delegate设为nil。在设置nil的使用最好使用[self setOjbect:nil];


其实上面的场景一般是针对在arc模式下,还使用了assign修饰符,如果使用weak修饰符,如果对象被销毁,会直接被置为nil,就不会出现crash的问题。



参考:

1、http://www.3lian.com/edu/2013/10-14/101566.html

2、http://blog.csdn.net/musou_ldns/article/details/7673795

3、http://blog.csdn.net/ashqal/article/details/12614901

4、http://segmentfault.com/q/1010000000127093

5、http://blog.csdn.net/jofranks/article/details/21244625


0 0