我正在为我的 children 在 iOS 中创建一个基本的猜谜游戏,我认为我对在应用程序的整个生命周期中应该如何创建和释放对象的理解存在一些根本性的差距。我一直在阅读有关保留和发布周期的内容,但我认为我的问题更多地与应用程序的基本架构有关,以及我在尝试实例化然后杀死应用程序的一些关键对象时可能表现不佳。
问题集中在两个特定的类上。
我有一个游戏类,我设计它来保存游戏运行所需的所有信息。当它被初始化时,它包含所有指向数组的实例变量,这些数组包含各种线索等字符串。它基本上是游戏所需的所有数据的容器。
我有一个游戏 View Controller ,它创建游戏类的一个实例并查询它,以便在屏幕上显示游戏对象包含的各种元素。
这很好用。当用户开始一个新游戏时,将分配并初始化游戏类的一个新实例,然后他们就可以离开了。
当我开始生成新游戏时,问题就来了。这会以多种方式发生。要么用户完成游戏并开始另一个游戏,要么用户退出当前游戏然后开始一个新游戏。
在我看来,我会释放游戏对象并分配并初始化一个新对象。但是,我注意到在设备上运行并通过分析器查看,游戏对象根本没有被释放。它仍然存在,并且游戏的每个实例化都会创建一个新的游戏对象,旧的仍然坐在那里没有指针
摆弄代码,我注意到我没有在 Game 类中实现 dealloc 方法...但是当我尝试这样做时,应用程序崩溃了,我怀疑是因为我正在尝试释放之前释放的对象.
理想情况下,我正在尝试做的是摆脱旧的 Game 对象,或者在每次开始新游戏时用新的对象替换旧的(覆盖)。
但是,这种做法错了吗?我应该以完全不同的方式来做吗?例如只创建一个游戏类的实例并在该类中重写一个方法以便在每次新游戏开始并且 GameViewController 告诉它时生成一组新的线索等?
是否有执行此操作的“最佳实践”方法?
所以您已经了解我在做什么,下面是 GameViewController 的代码,其中创建了 Game 类的实例:
#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];
}
具有 Game 类指定初始值设定项的游戏类(删节版):
#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;
}
最佳答案
第一个问题是 [super dealloc]
必须是您在 -dealloc
中做的最后一件事。这是因为实际上释放内存的是 NSObject 中的 dealloc
方法,所以当您返回它时,您的实例变量指针可能已经是垃圾了。
其他问题:
在 init 中,执行 self = [super init];
允许 super 对象在 init 上返回一个不同的 self 指针。
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];
}
您的代码主体中可能存在其他问题 - 确保您使用静态分析启用构建 - 它会捕获其中的许多问题。
关于objective-c - 基本 IOS OOP - 结构和实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7661052/