«Обмен» переменной экземпляра UIView - не может освободить «предыдущий» просмотр - PullRequest
1 голос
/ 02 декабря 2009

Я хочу как-то организовать уровни уровней в моей игре для iPhone, но я просто не могу (без расширения выделения объектов ). Я сделал действительно «скелет» своего кода (эта игра имеет 2 уровня, цель - выпустить дисплей iPhone). Я просто не могу освободить предыдущий уровень, поэтому Instrunments показывает увеличивающиеся экземпляры BGTangramLevel.

Пожалуйста, посмотрите, мне нужны полезные идеи по дизайну (мой третий вопрос по этому вопросу).

viewcontroller.h

@interface compactTangramViewController : UIViewController
{
    //The level.
    BGTangramLevel *currentLevel;
    UIColor *levelColor;
}

//It is to be just a reference, therefore I use assign here.
@property (nonatomic, retain) BGTangramLevel *currentLevel;

-(void) notificationHandler: (NSNotification*) notification;
-(void) finishedCurrentLevel;

@end

viewcontroller.m

@implementation compactTangramViewController
@synthesize currentLevel;

//Initializer functions, setting up view hierarchy.
-(void) viewDidLoad
{   

    //Set up levelstepper.
    levelColor = [UIColor greenColor];

    //Set up "state" classes.
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(notificationHandler:) name:@"finishedCurrentLevel" object:nil];   

    //Attach level 1.
    currentLevel = [BGTangramLevel levelWithColor: levelColor frame:self.view.frame];
    [self.view addSubview:currentLevel];

    [super viewDidLoad];

}

//Release objects.
-(void) dealloc
{
    [currentLevel release];
    [super dealloc];
}

//Notification handling.
-(void) notificationHandler: (NSNotification*) notification
{
    //Execute level swap.
    if ([notification name] == @"finishedCurrentLevel") [self finishedCurrentLevel];
}

-(void) finishedCurrentLevel
{
    //Remove previous level.
    [currentLevel removeFromSuperview];
    //[currentLevel release];

    //Step level.
    if (levelColor == [UIColor greenColor]) levelColor = [UIColor blueColor]; else levelColor = [UIColor greenColor];

    //Attach level 2.
    currentLevel = [BGTangramLevel levelWithColor: levelColor frame:self.view.frame];
    [self.view addSubview:currentLevel];

}
@end

BGTangramLevel.h

@interface BGTangramLevel : UIView
{
    BOOL puzzleCompleted;   
}

//Initializer.
+(BGTangramLevel*)levelWithColor: (UIColor*) color frame: (CGRect) frame;

//Test if the puzzle is completed.
-(void) isSolved;

@end

BGTangramLevel.m

@implementation BGTangramLevel

//Allocated instance.
+(BGTangramLevel*)levelWithColor: (UIColor*) color frame: (CGRect) frame
{
    BGTangramLevel *allocatedLevel = [[BGTangramLevel alloc] initWithFrame:frame];
    allocatedLevel.backgroundColor = color;
    return allocatedLevel;
}

//Finger released.
-(void) touchesEnded: (NSSet*)touches withEvent: (UIEvent*)event
{
    //The completement condition is a simple released tap for now...
    puzzleCompleted = YES;
    [self isSolved];    
}

//Test if the puzzle is completed.
-(void) isSolved
{
    //"Notify" viewController if puzzle has solved.
    if (puzzleCompleted) [[NSNotificationCenter defaultCenter] postNotificationName:@"finishedCurrentLevel" object:nil]; 
}

-(void) dealloc
{
    NSLog(@"Will ever level dealloc invoked."); //It is not.
    [super dealloc];
}

@end

Так что мне делать? Я попытался пометить авто-релиз экземпляра возвращаемого уровня, освободить currentLevel после removeFromSuperview, попытался синтезировать свойство currentLevel (неатомным, назначить), но распределение объектов все еще растет. Могу ли я избежать уведомлений? Я застрял.

1 Ответ

3 голосов
/ 02 декабря 2009

Вы должны более строго соблюдать правила сохранения / освобождения. Вы определенно не должны экспериментально добавлять retain и release и autorelease в местах, чтобы найти что-то, что работает. Уже много написано об управлении памятью Какао, я не буду повторять это здесь.

В частности, метод BGTangramLevel levelWithColor:frame: должен вызывать [allocatedLevel autorelease] перед возвратом allocLevel своему вызывающему. Он не владеет объектом, он остается за вызывающим абонентом.

Вам также необходимо знать разницу между доступом к переменной экземпляра и доступом к свойству. Свойства какао - просто синтаксический сахар для методов получения и установки. Когда вы ссылаетесь на currentLevel в вашем контроллере представления, вы имеете дело с переменной экземпляра напрямую. Когда вы ссылаетесь на self.currentLevel, вы имеете дело с собственностью.

Даже если вы объявили свойство, currentLevel = [BGTangram ...] просто копирует ссылку в переменную. В viewDidLoad вам нужно использовать self.currentLevel = [BGTangram ...], если вы хотите пройти через метод установки свойства, который сохранит объект (потому что вы объявили свойство таким образом). Видишь разницу?

Я думаю, что ваша утечка происходит в finishedCurrentLevel. Если бы вы использовали self.currentLevel = [BGTangram ...], вызывался бы метод установки свойства, который освободил бы старый объект и сохранил новый. Поскольку вы присваиваете переменную экземпляра напрямую, вы просто перезаписываете ссылку на старый уровень, не освобождая ее.

Вызов [currentLevel release] в методе dealloc вашего контроллера представления верен.

...