我是初学级程序员,试图为iphone制作游戏应用程序,到目前为止,我遇到了程序内存管理(exc_bad_access)可能存在的问题。我搜索并阅读了几篇关于内存管理的文章(包括苹果的文档),但我仍然无法弄清楚我的代码到底出了什么问题。所以如果有人可以帮我清理我为自己制造的烂摊子,我真的很感激。
//in the .h file
@property(nonatomic,retain) NSMutableArray *fencePoleArray;
@property(nonatomic,retain) NSMutableArray *fencePoleImageArray;
@property(nonatomic,retain) NSMutableArray *fenceImageArray;
//in the .m file
- (void)viewDidLoad {
[super viewDidLoad];
self.gameState = gameStatePaused;
fencePoleArray = [[NSMutableArray alloc] init];
fencePoleImageArray = [[NSMutableArray alloc] init];
fenceImageArray = [[NSMutableArray alloc] init];
mainField = CGRectMake(10, 35, 310, 340);
..........
[NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(gameLoop) userInfo:nil repeats:YES];
}
所以基本上,玩家触摸屏幕来设置围栏/杆
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
if(.......) {
.......
}
else {
UITouch *touch = [[event allTouches] anyObject];
currentTapLoc = [touch locationInView:touch.view];
NSLog(@"%i, %i", (int)currentTapLoc.x, (int)currentTapLoc.y);
if(CGRectContainsPoint(mainField, currentTapLoc)) {
if([self checkFence]) {
onFencePole++;
//this 3 set functions adds their respective objects into the 3 NSMutableArrays using addObject:
[self setFencePole];
[self setFenceImage];
[self setFencePoleImage];
.......
}
}
else {
.......
}
}
}
}
setFence函数(setFenceImage和setFencePoleImage与此类似)
-(void)setFencePole {
Fence *fencePole;
if (!elecFence) {
fencePole = [[Fence alloc] initFence:onFencePole fenceType:1 fencePos:currentTapLoc];
}
else {
fencePole = [[Fence alloc] initFence:onFencePole fenceType:2 fencePos:currentTapLoc];
}
[fencePoleArray addObject:fencePole];
[fencePole release];
每当我按下游戏中的按钮时,会调用endOpenState来清除屏幕上的所有额外图像(栅栏/柱子),并删除3 NSMutableArray中的所有现有对象。要点是删除NSMutableArrays中的所有对象,但保留数组本身,以便以后可以重用。
-(void)endOpenState {
........
int xMax = [fencePoleArray count];
int yMax = [fenceImageArray count];
for (int x = 0; x < xMax; x++) {
[[fencePoleImageArray objectAtIndex:x] removeFromSuperview];
}
for (int y = 0; y < yMax; y++) {
[[fenceImageArray objectAtIndex:y] removeFromSuperview];
}
[fencePoleArray removeAllObjects];
[fencePoleImageArray removeAllObjects];
[fenceImageArray removeAllObjects];
........
}
崩溃发生在checkFence函数。
-(BOOL)checkFence {
if (onFencePole == 0) {
return YES;
}
else if (onFencePole >= 1 && onFencePole < currentMaxFencePole - 1) {
CGPoint tempPoint1 = currentTapLoc;
CGPoint tempPoint2 = [[fencePoleArray objectAtIndex:onFencePole-1] returnPos]; // the crash happens at this line
if ([self checkDistance:tempPoint1 point2:tempPoint2]) {
return YES;
}
else {
return NO;
}
}
else if (onFencePole == currentMaxFencePole - 1) {
......
}
else {
return NO;
}
}
所以这里的问题是,一切正常,直到调用endOpenState后第二次调用checkFence。所以就像tap_screen - &gt; tap_screen - &gt; press_button_to_call_endOpenState - &gt;点击屏幕 - &gt; tap_screen - &gt;碰撞
我正在考虑的是当我使用[fencePoleArray removeAllObjects]时,fencePoleArray搞砸了,因为当我发表评论时它并没有崩溃。如果有人能向我解释出了什么问题,真的会很棒。并提前感谢。
答案 0 :(得分:0)
如果您想使用属性,则应使用self.propertyName = ...
代替propertyName = ...
。
希望这会有所帮助。
答案 1 :(得分:0)
首先,提出几点建议:
if (!elecFence) {
fencePole = [[Fence alloc] initFence:onFencePole
fenceType:1 fencePos:currentTapLoc];
}
else {
fencePole = [[Fence alloc] initFence:onFencePole
fenceType:2 fencePos:currentTapLoc];
}
你这太难了,怎么样:
const int fenceType = elecFence ? 2 : 1;
Fence *fencePole = [[Fence alloc] initFence:onFencePole
fenceType:fenceType fencePos:currentTapLoc];
而且:
int xMax = [fencePoleArray count];
int yMax = [fenceImageArray count];
for (int x = 0; x < xMax; x++) {
[[fencePoleImageArray objectAtIndex:x] removeFromSuperview];
}
for (int y = 0; y < yMax; y++) {
[[fenceImageArray objectAtIndex:y] removeFromSuperview];
}
可以使用makeObjectsPerformSelector:
const SEL remove = @selector(removeFromSuperview);
[fencePoleImageArray makeObjectsPerformSelector:remove];
[fenceImageArray makeObjectsPerformSelector:remove];
这更短更安全,因为代码中的xMax
绑定是从fencePoleArray
计算的,用于迭代fencePoleImageArray
。 (可能是对的,可能是错的。)
现在转到objectAtIndex:
电话。如果数组仍在内存中并且您尝试访问数组边界之外的对象,则会出现异常。所以我猜这个数组或其中的一些对象是在你不知道的情况下发布的。您可以尝试NSLog
数组和给定索引上的对象,并尝试记录它们的retainCount
。如果日志记录行崩溃,您已找到已释放的对象并可以开始查找原因。
(还有一件事:您应该将游戏逻辑拆分为一个单独的模型类。这样可以简化代码并使其更易于推理。)