2011-03-23 87 views
7

我是新來的可可/ objective-c,我正在爲我的對象發佈而感到苦惱。我有以下代碼:如何在forin循環中釋放對象?

gastroCategoryList = [[NSMutableArray alloc] init]; 
for (NSDictionary *gastrocategory in gastrocategories) { 
    NSString *oid = [gastrocategory objectForKey:@"id"]; 
    GastroCategory *gc = [[GastroCategory alloc] initWithId:[oid intValue] name:[gastrocategory objectForKey:@"name"]]; 
    [gastroCategoryList addObject:gc]; 
} 

分析儀顯示我的「gastrocategory」的定義爲是一種潛在的內存泄漏。但我不確定我是否可以在for循環結束時釋放它?

此外,在下面的代碼:

- (NSArray *)eventsForStage:(int)stageId { 

    NSMutableArray *result = [[NSMutableArray alloc] init]; 

    for (Event *e in eventList) { 
     if ([e stageId] == stageId) { 
      [result addObject:e]; 
     } 
    } 

    return result; 
} 

分析儀告訴我,我的「結果」是一個潛在的泄漏。但是我應該在哪裏發佈這個?

是否還有一個簡單的規則來記住,當我應該使用分配,複製,保留等在@property?

另一個問題:

- (IBAction)showHungryView:(id)sender { 
    GastroCategoriesView *gastroCategoriesView = [[GastroCategoriesView alloc] initWithNibName:@"GastroCategoriesView" bundle:nil]; 

    [gastroCategoriesView setDataManager:dataManager]; 

    UIView *currentView = [self view]; 
    UIView *window = [currentView superview]; 

    UIView *gastroView = [gastroCategoriesView view]; 

    [window addSubview:gastroView]; 

    CGRect pageFrame = currentView.frame; 
    CGFloat pageWidth = pageFrame.size.width; 
    gastroView.frame = CGRectOffset(pageFrame,pageWidth,0); 

    [UIView beginAnimations:nil context:NULL]; 
    currentView.frame = CGRectOffset(pageFrame,-pageWidth,0); 
    gastroView.frame = pageFrame; 
    [UIView commitAnimations]; 

    //[gastroCategoriesView release]; 
} 

我不明白這一點,在 「gastroCategoriesView」 是一個潛在的泄漏。我試圖在最後或autorelease釋放它,但都不能正常工作。每次我打電話給我的應用程序終止的方法。再一次非常感謝你!

回答

9

在你的循環,釋放每個gc其添加到列表中,因爲你不會需要它在你的循環範圍了之後:

gastroCategoryList = [[NSMutableArray alloc] init]; 
for (NSDictionary *gastrocategory in gastrocategories) { 
    NSString *oid = [gastrocategory objectForKey:@"id"]; 
    GastroCategory *gc = [[GastroCategory alloc] initWithId:[oid intValue] name:[gastrocategory objectForKey:@"name"]]; 
    [gastroCategoryList addObject:gc]; 
    [gc release]; 
} 

在你的方法,聲明result被自動釋放開脫的所有權它從你的方法:

NSMutableArray *result = [[[NSMutableArray alloc] init] autorelease]; 

// An alternative to the above, produces an empty autoreleased array 
NSMutableArray *result = [NSMutableArray array]; 

編輯:在你的第三個問題,你不能因爲它認爲正在使用的窗口釋放你的視圖控制器。將其設置爲autorelease也會導致相同的命運,只會延遲。

您必須在某處保留您的GastroCategoriesView控制器,在您的應用程序委託的實例變量中。

+0

非常感謝。你是否也知道@property問題的規則? – n3on 2011-03-23 19:15:08

+0

@ n3on:如果一個屬性被聲明爲'retain'或'copy',則應該在你的類的'dealloc'方法中釋放它的ivar。 – BoltClock 2011-03-23 19:16:43

+0

@BoltClock:好的,謝謝。但是,我應該何時使用複製,保留或分配? – n3on 2011-03-23 19:19:13

1

可以在將gc添加到gastroCategoryList之後釋放gc的原因是,當將對象添加到數組時,數組會保留該對象。所以,即使你釋放你的gc,它仍然會在周圍;由gastroCategoryList保留。

當您從一個方法返回一個新創建的對象時,您需要調用autorelease.這將導致只有在運行時間離開調用方法的範圍之後纔會釋放該對象,從而爲調用方法提供了一個機會有返回值的東西。

請注意,如果您的方法始於單詞副本或新的,那麼你應該而不是 autorelease你的對象;你應該讓它的調用方法釋放。

至於複製VS保留VS分配...作爲一般規則,複製具有可變版本的對象,如NSArray,NSSet,NSDictionary和NSString。這將確保你有一個指針的對象在你不想要的時候是不可變的。

否則,只要您希望確保對象仍在內存中,就使用retain。這將適用於除了被視爲對象父項的對象之外的幾乎每個對象,在這種情況下,您將使用assign。 (請參閱保留週期here一節)。

另請注意,您必須使用assign來分配非對象類型,例如int。

通過內存Management Programming Guide讀了一下;這很有幫助。

3

對於你的問題的第一部分,BoltClock的答案是肯定的。我會盡力解決其餘問題。

賦值適用於簡單的非對象類型,如int,double或struct。它會生成一個執行普通舊賦值的setter,如在「foo = newFoo」中。複製&保留意願,如他們的名字暗示,或者複製新值(「foo = [newFoo copy]」)或保留它(「foo = [newFoo retain]」)。在這兩種情況下,二傳手都會酌情釋放舊值。

所以問題是,何時複製以及何時保留。答案是......這取決於。你的班級如何使用新的價值?如果其他代碼修改了傳入對象,你的類是否會中斷?比如說,你有一個名爲「theString」的NSString *屬性。其他代碼可以將一個NSMutableString實例分配給該字符串 - 這是合法的,因爲它是一個NSString子類。但是其他代碼也可能保留自己對可變字符串對象的引用,並更改它的值 - 您的代碼是否準備好處理這種可能性?如果不是,它應該製作自己的副本,其他代碼不能更改。另一方面,如果你自己的代碼沒有假設字符串是否可能被改變,並且不管它是否工作正常,那麼你可以通過保留傳入對象而不是不必要地製造內存來節省內存它的副本。

基本上,不幸的是,有時並不那麼簡單的規則是仔細考慮自己的代碼是否需要自己的私人副本,或者是否可以正確處理其值可能被其他代碼更改的共享對象。

+0

有時候你需要在對象類型上使用賦值。它不僅適用於非對象類型。 – GendoIkari 2011-03-23 19:29:00

+0

真 - 保留週期,代表和連接的IBOutlet,僅舉幾例。我試圖保持簡單,但可能已經簡化了很多。 – 2011-03-23 19:35:32

+0

我一直保留IBOutlets ...是否有理由讓他們分配?他們是否被你自己的管理員課程以外的任何東西保留? – GendoIkari 2011-03-23 19:38:32