2010-04-05 50 views
1

我是一名嘗試爲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; 
    } 
} 

所以這裏的問題是,一切工作正常,直到checkFence調用endOpenState後第二次調用。因此,它像tap_screen - > tap_screen - > press_button_to_call_endOpenState - >自來水屏幕 - > tap_screen - >崩潰

的我在想什麼是fencePoleArray弄亂,當我用[fencePoleArray removeAllObjects],因爲它不會崩潰的時候我評論一下。如果有人能向我解釋出了什麼問題,那真的很棒。並提前致謝。

+0

你在endOpenState復位onFencePole和currentMaxFencePole?如果不是,它看起來像你的代碼可以訪問(現在是空的)數組末尾的東西。 – user308405 2010-04-05 06:34:44

+0

這會拋出異常,不是嗎? – zoul 2010-04-05 06:41:27

+0

是的,我重置onFencePole和currentMaxFencePole。 – Treon 2010-04-05 07:14:58

回答

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

這會更短更安全,因爲代碼中的xMaxfencePoleArray開始計算並用於迭代fencePoleImageArray。 (可能是對的,可能是錯的。)

現在撥打objectAtIndex:。如果數組仍然在內存中,並且您試圖訪問超出數組邊界的對象,則會發生異常。因此,我猜想數組或其中的某些對象在您不知情的情況下被釋放。您可以嘗試NSLog陣列和給定索引上的對象,並嘗試記錄它們的retainCount。如果日誌記錄行崩潰,則已找到已釋放的對象並可開始查找原因。

(還有一兩件事:你應該在遊戲邏輯拆分成一個獨立的模型類,簡化了代碼,並使得它更容易推理。)

+0

感謝您的建議,但它仍然沒有幫助我解決內存問題。我沒有使用NSZombieEnabled變量的測試,我得到它說一個錯誤信息: *** - [護欄returnPos]:發送到釋放實例0x3933000 我假設我fencePoleArray確實得到了釋放的消息,但我看不出過度釋放發生在哪裏。 – Treon 2010-04-05 06:41:33

+0

太棒了,你已經差不多了。現在你所要做的就是在'Fence'的'release'方法中設置一個斷點,並查看你釋放實例的位置。發現罪犯應該只需要幾分鐘的時間(查看堆棧跟蹤)。 – zoul 2010-04-05 06:49:07

+0

我該怎麼做?我已經檢查了我的代碼,但我從來沒有明確放過任何代碼來釋放我的fencePoleArray。最接近的匹配是[fencePoleArray removeAllObjects],它只釋放數組中的對象,但保留數組本身(這是我的假設,即使當內部的所有對象都被刪除時,數組仍然保留,所以如果我錯了,請糾正我)。 – Treon 2010-04-05 06:55:27

0

如果你想使用屬性,你應該使用self.propertyName = ...而不是propertyName = ...

希望這會有所幫助。

+0

究竟在哪裏?在'viewDidLoad',這實際上會導致泄漏。 – zoul 2010-04-05 06:47:39