iOS中常见 Crash 及解决方案

  • Post author:
  • Post category:其他


转自微信公众号:iOS大全





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



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

例子:

NSObject *aObj = [[NSObjectalloc]init];
[aObj release];
 
NSLog(@"%@",aObj);

原因:

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

解决办法:

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

[aObj release];
aObj = nil;

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

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

if(aObj){
    //...
}

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

if(aString && aString.length > 0){//...}

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

@autoreleasepool{
    for(inti = 0;i < 100; ++i){
        NSObject * aObj = [[[NSObjectalloc] init] autorelease];
        //....
    }
}





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



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

原因:

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

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

[array addObject:[NSNullnull]];


解决办法:

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

if(aObj){
    [array addObject:aObj];
}

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

@interface NSMutableArray(SafeInsert)
-(void)safeAddObject:(id)anObject;
@end
 
@implementation NSMutableArray(SafeInsert)
-(void)safeAddObject:(id)anObject{
    if(anObject){
        [self addObject:anObject];
    }
}
@end

这样,以后在工程里面使用 NSMutableArray 就可以直接使用 safeAddObject 方法来规避 Crash。





三、访问了不存在的方法




Ob



版权声明:本文为xgcyangguang原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。