释放数组会使应用程序在 xCode 中崩溃

Posted

技术标签:

【中文标题】释放数组会使应用程序在 xCode 中崩溃【英文标题】:Releasing an Array crashes the app in xCode 【发布时间】:2012-02-07 15:33:16 【问题描述】:

为什么我的应用在释放数组时会崩溃?我一直试图弄清楚几个小时!如果我不释放它,它会导致内存泄漏。如果我确实释放它,它会因以下错误而崩溃: 程序接收信号:“EXC_BAD_ACCESS”。 有时它也这样说: 数据格式化程序暂时不可用,将在“继续”后重试。 (此时调用 dlopen 不安全。)

就是想不通。代码很多,所以我将粘贴(我认为的)相关部分。

-(void)startGame:(int)levelNumber 

    //NOTE there is some code ive not pasted as its too big, but I dont think its relevant

levelsArray = [gameLevels loadLevelMap:levelNumber];
levelsArray_charGuards = [[levelsArray objectAtIndex:4]retain];


    //CREATE CHAR MAIN ########
charMainStore = [[NSMutableArray arrayWithCapacity:1] retain];

charMainToDestroy = [[NSMutableArray arrayWithCapacity:1] retain];

CharMain* charMain = [[CharMain alloc] initWithFrame:CGRectMake(((levels_charStart_x)*40), ((levels_charStart_y)*40), 0, 0)];
[viewController.mapView addSubview:charMain];

[self registerMainChar:charMain];
charMain.gameController = self;
charMain.currentGrid_x = levels_charStart_x;
charMain.currentGrid_y = levels_charStart_y;
charMain.nextGrid_x = levels_charStart_x;
charMain.nextGrid_y = levels_charStart_y;
mapViewController.gameController = self;

[self moveMap_x:((levels_charStart_x)*40) moveMap_y:((levels_charStart_y)*40)];

[charMain release];

 //CREATE CHAR GUARD ######## 
charGuardStore = [[NSMutableArray arrayWithCapacity:10] retain];
charGuardToDestroy = [[NSMutableArray arrayWithCapacity:10] retain]; 
    //These are both @synthesize properly
    //levelsArray_charGuards is from previously

    for (NSMutableArray* levelsArray_charGuards_path in levelsArray_charGuards) 

    NSMutableArray* levelsArray_charGuards_path_eachCoOrd = [levelsArray_charGuards_path objectAtIndex:0];

    int levels_charGuardStart_x = [[NSString stringWithFormat:@"%@",[levelsArray_charGuards_path_eachCoOrd objectAtIndex:0]] intValue];
    int levels_charGuardStart_y = [[NSString stringWithFormat:@"%@",[levelsArray_charGuards_path_eachCoOrd objectAtIndex:1]] intValue];

    CharGuard* charGuard = [[CharGuard alloc] initWithFrame:CGRectMake((levels_charGuardStart_x*40), (levels_charGuardStart_y*40), 0, 0)];
    //CharGuard* charGuard = [[CharGuard alloc] initWithFrame:CGRectMake(((levels_charStart_x)*40), ((levels_charStart_y)*40), 0, 0)];

    [viewController.mapView addSubview:charGuard];

    [self registerGuardChar:charGuard];
    charGuard.gameController = self;
    [charGuard setImage];
    charGuard.currentGrid_x = levels_charGuardStart_x;
    charGuard.currentGrid_y = levels_charGuardStart_y;
    charGuard.nextGrid_x = levels_charGuardStart_x;
    charGuard.nextGrid_y = levels_charGuardStart_y;
    mapViewController.gameController = self;

    charGuard.levelsArray_charGuards_path = levelsArray_charGuards_path;

    [charGuard release];
    charGuard = nil;


    levelsArray_charGuards_path = nil;

    levelsArray_charGuards_path_eachCoOrd =nil;


当一个级别完成或重新启动时,这被称为:

-(void)clearLevel 
NSLog(@"Clear Level");

    for (CharMain* charMain in charMainStore)

    [charMain removeFromSuperview];
    [charMainToDestroy addObject:charMain];


for (CharMain* charMain in charMainToDestroy)

    [charMainStore removeObject:charMain];



for (CharGuard* charGuard in charGuardStore) 

    [charGuard removeFromSuperview];
    [charGuardToDestroy addObject:charGuard];



for (CharGuard* charGuard in charGuardToDestroy)

    [charGuardStore removeObject:charGuard];



    [charGuardStore release];
charGuardStore=nil;

[charMainStore release];
charMainStore=nil;

//[charGuardToDestroy release]; //If I allow this it crashes!***********
charGuardToDestroy= nil;

[charMainToDestroy release];
charMainToDestroy = nil;


然后游戏再次调用 startGame:(int)levelNumber。

我还有其他我没有在这里展示的对象,但它们都可以正常工作。就是不想被释放的charGuardToDestroy!

我试过了:

-(void)clearLevel 
NSLog(@"Clear Level");

    for (CharMain* charMain in charMainStore)

    [charMain removeFromSuperview];
    [charMainToDestroy addObject:charMain];


for (CharMain* charMain in charMainToDestroy)

    [charMainStore removeObject:charMain];



for (CharGuard* charGuard in charGuardStore) 

    [charGuard removeFromSuperview];
    //[charGuardToDestroy addObject:charGuard];


/*
for (CharGuard* charGuard in charGuardToDestroy)

    [charGuardStore removeObject:charGuard];


    */

    [charGuardStore release];
charGuardStore=nil;

[charMainStore release];
charMainStore=nil;

[charGuardToDestroy release]; //I tried allowing this and removing the above code ***********
charGuardToDestroy= nil;

[charMainToDestroy release];
charMainToDestroy = nil;


这也有效,但为什么呢?我真的需要能够从屏幕和阵列中删除 charGuard,然后释放它,但我只能做一个或另一个。很奇怪!

【问题讨论】:

【参考方案1】:

您很可能在某个地方向数组 charGuardStore 添加了一个 CharGuard 对象,该对象仅由该数组和 charGuards 超级视图保留。

这是我认为会发生的事情:

for (CharGuard* charGuard in charGuardStore) 

    [charGuard removeFromSuperview];             // charGuard only retained by charGuardStore (= 1 retain left)
    [charGuardToDestroy addObject:charGuard];    // charGuard retained by charGuardToDestroy too (= 2 retains left)



for (CharGuard* charGuard in charGuardToDestroy)

    [charGuardStore removeObject:charGuard];     // remove 1 retain (= 1 retain left) because it's still in charGuardToDestroy



/* more code */

[charGuardToDestroy release];                    // remove all charGuards. charGuard gets released. And most likely you access it later. 

所以您的错误很可能在您创建 CharGuard 时已经发生。可能是过度释放,但效果要晚得多。

使用NSZombieEnabled 确定是否是这种情况。

我认为如果在从该数组中删除 charGuard 之后添加 [charGuardToDestroy removeAllObjects];,它会崩溃。这将证实我所说的。

【讨论】:

谢谢。我使用了 Zombies(我不知道它存在,因为它是灰色的),但这很好用并且发现了一些其他错误。是否 [charGuard removeFromSuperview];还释放 charGuard?我认为部分问题出在 charGuard 中,在 -(void)dealloc 下我发布了之前设置的 charImage: NSString* tempStr = [NSString stringWithFormat:@"char_guard_%d_%d",2,1]; UIImage* loadedImage = [UIImage imageNamed:tempStr]; charImage = [loadedImage 保留];我认为这应该已经发布了。 很抱歉回答迟了。是的,removeFromSuperview 将释放对象 1 次。此版本只是为了解决当您将带有addSubView: 的视图添加到之前的另一个视图时引起的保留。看起来你保留了 charImage,所以你必须在 dealloc 中释放它。既然您将我的答案标记为正确,我希望您能理解。不幸的是,有时很难找到内存错误。

以上是关于释放数组会使应用程序在 xCode 中崩溃的主要内容,如果未能解决你的问题,请参考以下文章

发布 OpenCV IplImage 会使应用程序崩溃?

使用 NSUserDefaults 保存数组会使应用程序崩溃

为啥大型本地数组会使我的程序崩溃,而全局数组却不会? [复制]

保存在 userdefaults 中会使应用程序崩溃

向现有 xcdatamodel 添加属性会使 Xcode 4.2 崩溃

自动释放池导致 RubyCocoa 应用程序崩溃