2009-12-02 44 views
1

我想組織某種程度上我的iPhone遊戲的水平視圖,但我根本無法(沒有展開對象分配)。我做了一個真正的「骨架」我的代碼(這個遊戲有2個關卡,目標是發佈iPhone顯示屏)。我不能釋放前一級,因此Instrunments會顯示增加BGTangramLevel實例。「交換」一個UIView實例變量 - 不能dealloc「先前」視圖

請看看它,我需要一些有用的想法設計(我的第三個問題)。

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 

那麼我該怎麼做?我嘗試標記autorelease返回的級別實例,在removeFromSuperview後釋放currentLevel,嘗試以(非原子,分配)方式合成的currentLevel屬性,但Object Allocations仍在增長。我可以避免通知嗎?我卡住了。

回答

3

您需要更緊密地遵循保留/釋放規則。你絕對不應該在實驗上添加保留,釋放和自動釋放,只是爲了找到有用的東西。已經有很多關於Cocoa內存管理的文章,我不會在這裏重複。

具體來說,BGTangramLevel的levelWithColor:frame:方法在返回其調用者之前應該調用[allocatedLevel autorelease]。它不擁有該對象,取決於調用者。

您還需要知道訪問實例變量和訪問屬性之間的區別。可可的屬性只是用於吸氣和吸氣方法的語法糖。當您在視圖控制器中引用currentLevel時,您正在直接處理實例變量。當你參考self.currentLevel你正在處理財產。

即使您已聲明屬性,currentLevel = [BGTangram ...]只是將引用複製到變量中。在viewDidLoad中,如果您想要通過屬性的setter方法,您將需要使用self.currentLevel = [BGTangram ...],該方法將保留該對象(因爲您以這種方式聲明屬性)。看到不同?

我認爲你的泄漏發生在finishedCurrentLevel。如果您使用過self.currentLevel = [BGTangram ...],則會調用該屬性的setter方法,該方法將釋放舊對象並保留新對象。由於您直接分配給實例變量,因此只需將舊引用覆蓋而不釋放它。

在您的視圖控制器的dealloc方法中調用[currentLevel release]是正確的。

+0

聽起來很有希望。我期待着對它進行測試。是的,返回[allocLevel autorelease];由於事故而跳過。這些分配器/初始化器應該返回autorelease標記的對象,這很清楚。大多數答案建議使用合成訪問器,我相信我確實使用它們。我試圖自己實現訪問器以確保釋放/保留,但是沒用,因爲我從來沒有用簡單的currentLevel = [...賦值來調用它們。希望self.currentLevel = [...幫助。再次感謝。 – Geri 2009-12-02 08:57:41

+0

還有一個問題。假設我得到/設置了槽訪問器,在調用removeFromSuperview(作爲文檔聲明)之前,我是否已經手動保留一次currentLevel?嗯...不要想,因爲我想讓BGTangramLevel實例在那裏釋放。 – Geri 2009-12-02 09:02:51

+0

視圖保留其子視圖,所以'addSubview:'是一個隱式的'retain','removeFromSuperview'是一個隱式的'release'。 但是,由於您的控制器負責保留和釋放currentLevel,因此您不必關心其他人是否也這樣做。 該文檔只是指出,在不保留視圖的情況下調用'removeFromSuperview'是一個常見的錯誤,在這種情況下,它將立即解除分配。 – benzado 2009-12-03 08:20:18