2010-04-05 3 views
1

저는 초급 수준의 프로그래머로서 아이폰 용 게임 응용 프로그램을 만들려고 노력 중이며 지금까지 프로그램의 메모리 관리 (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 -> tap_screen -> press_button_to_call_endOpenState -> 탭 화면 -> tap_screen -> 충돌

내가 생각하고있어의 내가 사용하는 경우 fencePoleArray이 엉망이있어이다 [fencePoleArray는 removeAllObjects]이 때 충돌하지 않기 때문에 나는 그것을 주석 처리한다. 누군가가 나에게 무엇이 잘못되었는지 설명 할 수 있다면 정말 좋을 것입니다. 그리고 미리 감사드립니다.

+0

당신이 endOpenState에 onFencePole 및 currentMaxFencePole를 재설정하고 있습니까? 그렇지 않으면 코드가 (이제 비어있는) 배열의 끝에서 액세스 할 수있는 것처럼 보입니다. – user308405

+0

그것은 예외를 던질 것입니다, 그렇지 않습니까? – zoul

+0

예 onFencePole 및 currentMaxFencePole을 재설정했습니다. – Treon

답변

0

첫째, 몇 가지 제안 :

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]; 
} 

단축 할 수 이것에 대해 어떻게 당신이 너무 열심히 만들고있어

if (!elecFence) { 
    fencePole = [[Fence alloc] initFence:onFencePole 
     fenceType:1 fencePos:currentTapLoc]; 
} 
else { 
    fencePole = [[Fence alloc] initFence:onFencePole 
     fenceType:2 fencePos:currentTapLoc]; 
} 

, 를 사용하여 makeObjectsPerformSelector:

const SEL remove = @selector(removeFromSuperview); 
[fencePoleImageArray makeObjectsPerformSelector:remove]; 
[fenceImageArray makeObjectsPerformSelector:remove]; 

코드에서 바운드 된 xMaxfencePoleArray에서 계산되고 fencePoleImageArray을 반복하는 데 사용되므로 더 짧아지고 안전합니다. (맞을 수도 틀릴 수도 있습니다.)

이제 objectAtIndex:으로 전화하십시오. 배열이 여전히 메모리에 있고 배열 범위를 벗어난 객체에 액세스하려고 시도하면 예외가 발생합니다. 배열이나 객체의 일부가 여러분이 알지 못하는 사이에 해제되었다고 생각합니다. 당신은 NSLog 배열과 주어진 인덱스에있는 객체를 시도하고 그들의 retainCount을 기록하려고 시도 할 수 있습니다.로깅 행이 충돌하면 릴리스 된 객체를 찾고 원인 찾기를 시작할 수 있습니다.

(그리고 한 가지 더 :. 당신은 별도의 모델 클래스로 게임 로직을 분리해야이 코드를 단순화하고 추론하기가 쉬워집니다.)

+0

제안 해 주셔서 감사합니다. 그러나 여전히 메모리 문제로 인해 도움이되지 않았습니다. NSZombieEnabled 변수를 사용하여 테스트를 수행했으며 다음과 같은 오류 메시지가 나타납니다. *** - [울타리 returnPos] : 메시지가 할당 취소 된 인스턴스로 전송 됨 0x3933000 내 fencePoleArray가 실제로 과도하게 공개되었지만 과도한 발표가 어디에서 발생했는지 나는 알 수 없다. – Treon

+0

대단하다. 거의 다 알았다. 이제 당신은'Fence'의'release' 메소드에 중단 점을 설정하고 인스턴스를 어디에서 놓을지를 알아야합니다. 가해자를 발견하는 데 몇 분이 걸릴 것입니다 (스택 추적을보십시오). – zoul

+0

어떻게하면됩니까? 내 코드를 살펴 봤지만 내 fencePoleArray를 해제 할 코드를 명시 적으로 넣지 않았습니다. 가장 가까운 일치 항목은 [fencePoleArray removeAllObjects]로 이동하지만 배열 내부의 객체 만 해제하지만 배열 자체는 유지됩니다. 이는 배열이 내부의 모든 객체가 제거 된 경우에도 유지된다는 내 가정이므로 잘못된 경우 수정하십시오. – Treon

0

속성을 사용하려면 propertyName = ... 대신 self.propertyName = ...을 사용해야합니다.

희망이 도움이 될 것입니다.

+0

정확히 어디입니까? 'viewDidLoad'에서 실제로 누출을 일으킬 것입니다. – zoul

관련 문제