释放数组会使应用程序在 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 中崩溃的主要内容,如果未能解决你的问题,请参考以下文章
使用 NSUserDefaults 保存数组会使应用程序崩溃
为啥大型本地数组会使我的程序崩溃,而全局数组却不会? [复制]