2011-10-05 29 views
0

我在iOS中爲我的孩子創建了一個基本的猜謎遊戲,我認爲在我理解應該如何在應用程序的整個生命週期中創建和釋放對象方面存在一些根本性的差距。我一直在閱讀關於保留和釋放週期的內容,但我認爲我的問題更多的是與應用程序的基本架構有關,以及我可能很難嘗試實例化並殺死應用程序的幾個關鍵對象。基本的IOS OOP - 結構和實現

問題集中在兩個特定的類上。

我有一個遊戲課程,我設計用來保存遊戲運行所需的所有信息。當它被初始化時,它將保存所有指向包含各種線索等字符串的數組的實例變量。它基本上是遊戲需要的所有數據的容器。

我有一個遊戲視圖控制器,它創建遊戲類的一個實例並查詢它,以便在屏幕上呈現包含在遊戲對象中的各種元素。

這工作得很好。當用戶開始一個新的遊戲時,一個新的遊戲類實例被分配並初始化並離開它們。

當我開始生成新遊戲時,問題就出現了。這發生在很多方面。用戶完成遊戲並啓動另一個遊戲,或者用戶退出當前遊戲,然後啓動一個新遊戲。

在我的想法中,我只是釋放遊戲對象和alloc並初始化一個新的。但是,我注意到在設備上運行並查看剖析器,發現遊戲對象完全沒有釋放。它仍然存在,遊戲的每個實例都創建一個新的遊戲對象,而舊遊戲對象仍然坐在那裏,沒有指針到它。

擺弄代碼,我注意到我沒有在Game類中實現dealloc方法......但是當我嘗試這樣做時,應用程序崩潰了,我懷疑是因爲我試圖釋放以前發佈的目的。

理想情況下,我想要做的是擺脫舊的遊戲對象,或每次新遊戲開始時用新遊戲對象替換舊遊戲對象(覆蓋)。

但是,這種方法是錯誤的嗎?我應該做一個完全不同的方式嗎?比如在創建遊戲類的單個實例並重寫該類中的方法以便生成一組新的線索等時,每當新遊戲開始並且GameViewController告訴它時?

有沒有一個'最佳實踐'的方式來做到這一點?

所以,你有我在做什麼的想法,代碼如下的GameViewController,其中創建遊戲類的一個實例:

#import "GameViewController.h" 

@implementation GameViewController 

@synthesize game = _game; 


-(void)startNewGameOfLevel:(NSInteger)level 
    { 
     if(!_game) 
     { 
      Game *g = [[Game alloc]initGamewithLevel:level]; 
      [self setGame:g]; 
      [g release]; g = nil; 
     } 

     [self set_currentlevel:[_game _currentLevel]]; 

     // set up popover to show the rounds goal letter 
     [self setUpPopOver]; 

    } 

-(void)quitTheCurrentGameAndStartNewGame 
{ 
    [_game release]; _game = nil; 
    [self clearGamePlayingField]; 
    animationStepIndex = 0; 
    [self startNewGameOfLevel: _currentlevel]; 
} 

遊戲類(略)與指定的初始化遊戲類:

#import "Game.h" 


    @implementation Game 

    @synthesize arrayOfLowerCaseLetters = _arrayOfLowerCaseLetters; 
    @synthesize arrayOfPhrases= _arrayOfPhrases; 

    @synthesize goalLetter = _goalLetter; 
    @synthesize goalPhrase = _goalPhrase; 
    @synthesize gameLetterPool = _gameLetterPool; 

    @synthesize _indexForGoalLetter, _numberOfLevelsInGame, _currentLevel, _numberOfWhackHoles, _numberOfLettersInGameLetterPool; 

    -(id)initGamewithLevel:(NSInteger)level 
    { 
     [super init]; 

     //create an array of lower case letters. These will 
     //contain the full alphabet of all possible letters 

     NSArray *arrayOfLCLetters = [[NSArray alloc] initWithObjects:@"a", @"b", @"c", @"d",@"e", @"f", @"g", @"h", @"i", @"j", @"k", @"l", @"m", @"n", @"o", @"p", @"qu", @"r", @"s", @"t", @"u", @"v", @"w", @"x",@"y", @"z",@"ch", @"sh", @"th", nil]; 
     [self setArrayOfLowerCaseLetters: arrayOfLCLetters]; 
     [arrayOfLCLetters release];arrayOfLCLetters = nil; 

     //create an array of phrases. 
     // These must correspond with each of the letters. e.g. a = apple. 

     NSArray *phrases= [[NSArray alloc ] initWithObjects: 
          @"apple", 
          @"butterfly", 
          @"cat", 
          @"dog", 
          @"egg", 
          @"frog", 
          @"ghost", 
          @"horse", 
          @"igloo", 
          @"jam", 
          @"kite", 
          @"leaf", 
          @"moon", 
          @"nut", 
          @"orange", 
          @"pig", 
          @"queen", 
          @"rabbit", 
          @"snake", 
          @"tree", 
          @"umbrella", 
          @"van", 
          @"water", 
          @"x-ray", 
          @"yak", 
          @"Zebra", 
          @"chair", 
          @"shoes", 
          @"thumb", 

          nil]; 
     [self setArrayOfPhrases:phrases]; 
     [phrases release]; phrases = nil; 


     //choose a random number to be the index reference for 
     // each goal letter and goal phrase. 
     [self set_indexForGoalLetter:(arc4random()%[_arrayOfLowerCaseLetters count])]; 
     NSLog(@"index for goal letter is:, %i", _indexForGoalLetter); 

     //set Goal letter and goal phrase 
     [self setGoalLetter: [_arrayOfLowerCaseLetters objectAtIndex: _indexForGoalLetter]]; 
     [self setGoalPhrase: [_arrayOfPhrases objectAtIndex:_indexForGoalLetter ]]; 

     //set current level 
     [self set_currentLevel: level]; 
     //[self set_currentLevel: 2]; 


     //set number of whackholes by level 
     [self set_numberOfWhackHoles: [self numberOfWhackHolesByLevel:_currentLevel]]; 

     //generate size of Letter pool by level 
     [self set_numberOfLettersInGameLetterPool:[self numberOfLettersInLetterPoolbyLevel:_currentLevel]]; 

     //////////////////////////// 
     /// Game letter pool 
     /////////////////////////// 

     //set up array ton hold the pool of letters 
     NSMutableArray *gp = [[NSMutableArray alloc] initWithCapacity:_numberOfLettersInGameLetterPool]; 
     [self setGameLetterPool: gp]; 
     [gp release];gp = nil; 

     //add the goal letter to this pool 
     [_gameLetterPool addObject:_goalLetter]; 

     int i = 1; 

     while (i < _numberOfLettersInGameLetterPool) { 
      NSString *letter = [_arrayOfLowerCaseLetters objectAtIndex:(arc4random()%[_arrayOfLowerCaseLetters count])]; 
      if ([_gameLetterPool containsObject:letter] == false) 
      { 
       [_gameLetterPool addObject:letter]; 
       i++; 
      } 

     } 

     NSLog(@"********** Game created ***************"); 
     NSLog(@"pool of letters is: %@", [_gameLetterPool description]); 
     NSLog(@"****************************************"); 
     NSLog(@"current goal letter is: %@", _goalLetter); 
      NSLog(@"****************************************"); 
     NSLog(@"current goal phrase is: %@", _goalPhrase); 
      NSLog(@"****************************************"); 

     return self; 
    } 

-(void)dealloc 
{ 
    [super dealloc]; 
    [_arrayOfLowerCaseLetters release]; _arrayOfLowerCaseLetters = nil; 
    [_arrayOfPhrases release]; _arrayOfPhrases = nil; 
    [_goalLetter release];_goalLetter = nil; 
    [_goalPhrase release]; _goalPhrase = nil; 
    [_gameLetterPool release];_gameLetterPool = nil; 
} 

回答

2

的頭號問題是[super dealloc]一定是你在做-dealloc絕對的最後一件事。這是因爲它是NSObject中的dealloc方法,它實際上釋放了內存,所以當你回到它的時候,你的實例變量指針可能已經是垃圾了。

其他問題:

在初始化,做self = [super init];超級對象被允許在初始化返回不同的自指針。

startNewGameOfLevel:quitTheCurrentGameAndStartNewGame應該使用該屬性,而不是裸露的實例變量。

-(void)startNewGameOfLevel:(NSInteger)level 
    { 
     if(![self game]) 
     { 
      Game *g = [[Game alloc]initGamewithLevel:level]; 
      [self setGame:g]; 
      [g release]; g = nil;// g = nil, not necessary when it's about to go out of scope 
     } 

     [self set_currentlevel:[[self game] _currentLevel]]; // don't use _ to start methods - Apple reserves this convention 

     // set up popover to show the rounds goal letter 
     [self setUpPopOver]; 

    } 

-(void)quitTheCurrentGameAndStartNewGame 
{ 
    [self setGame: nil]; 
    [self clearGamePlayingField]; 
    animationStepIndex = 0; 
    [self startNewGameOfLevel: _currentlevel]; 
} 

有可能在你的代碼的身體的其他問題 - 請務必建立與靜態分析讓 - 這將趕上很多。