iOS中常见 Crash 及解决方案

388 查看

一、访问了一个已经被释放的对象

在不使用 ARC 的时候,内存要自己管理,这时重复或过早释放都有可能导致 Crash。

例子

原因

aObj 这个对象已经被释放,但是指针没有置空,这时访问这个指针指向的内存就会 Crash。

解决办法

  • 使用前要判断非空,释放后要置空。正确的释放应该是:

    由于ObjC的特性,调用 nil 指针的任何方法相当于无作用,所以即使有人在使用这个指针时没有判断至少还不会挂掉。

    在ObjC里面,一切基于 NSObject 的对象都使用指针来进行调用,所以在无法保证该指针一定有值的情况下,要先判断指针非空再进行调用。

    常见的如判断一个字符串是否为空:

  • 适当使用 autorelease。有些时候不能知道自己创建的对象什么时候要进行释放,可以使用 autoRelease,但是不鼓励使用。因为 autoRelease 的对象要等到最近的一个 autoReleasePool 销毁的时候才会销毁,如果自己知道什么时候会用完这个对象,当然立即释放效率要更高。如果一定要用 autoRelease 来创建大量对象或者大数据对象,最好自己显式地创建一个 autoReleasePool,在使用后手动销毁。以前要自己手动初始化 autoReleasePool,现在可以用以下写法:

二、访问数组类对象越界或插入了空对象

NSMutableArray/NSMutableDictionary/NSMutableSet 等类下标越界,或者 insert 了一个 nil 对象。

原因

一个固定数组有一块连续内存,数组指针指向内存首地址,靠下标来计算元素地址,如果下标越界则指针偏移出这块内存,会访问到野数据,ObjC 为了安全就直接让程序 Crash 了。

而 nil 对象在数组类的 init 方法里面是表示数组的结束,所以使用 addObject 方法来插入对象就会使程序挂掉。如果实在要在数组里面加入一个空对象,那就使用 NSNull

解决办法

使用数组时注意判断下标是否越界,插入对象前先判断该对象是否为空。

可以使用 Cocoa 的 Category 特性直接扩展 NSMutable 类的 Add/Insert 方法。比如: