2009-08-27 63 views
2

我是Objective-C的新手,我對如何管理下面顯示的本地NSString變量以及類對象內的相關實例變量的內存有點好奇。我的代碼工作正常,但對最佳實踐感到好奇。爲NSString分配內存?

編輯包括完整的代碼,沒什麼特別的,就像我說我只是好奇,如果在這種情況下,我應該做的NSString對象的分配/釋放。

// MAIN ------------------------------------------------------------------- ** 
#import <Foundation/Foundation.h> 
#import "PlanetClass.h"; 

int main (int argc, const char * argv[]) { 

    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 

    NSString *planet_01_Geek; 
    NSString *planet_02_Geek; 

    // Create planets 
    PlanetClass *newPlanet_01 = [[PlanetClass alloc] init]; 
    [newPlanet_01 setGeekName:@"StarWars"]; 
    PlanetClass *newPlanet_02 = [[PlanetClass alloc] init]; 
    [newPlanet_02 setGeekName:@"Dune"]; 

    // Query a planet 
    planet_01_Geek = [newPlanet_01 geekName]; 
    planet_02_Geek = [newPlanet_02 geekName]; 

    // Print details 
    NSLog(@"Planet Geek = %@", planet_01_Geek); 
    NSLog(@"Planet Geek = %@", planet_02_Geek); 

    // Clean up 
    [newPlanet_01 release]; 
    [newPlanet_02 release]; 
    [pool drain]; 
    return 0; 
} 

..

// CLASS HEADER ----------------------------------------------------------- ** 
#import <Foundation/Foundation.h> 

@interface PlanetClass : NSObject { 
NSString *geekName; 
} 

- (NSString*) geekName; 
- (void) setGeekName:(NSString*)gName; 
@end 
// ------------------------------------------------------------------------ ** 

..

// CLASS BODY ------------------------------------------------------------- ** 
#import "PlanetClass.h" 

@implementation PlanetClass 

- (NSString*)geekName { 
    return geekName; 
} 
- (void)setGeekName:(NSString*)gName { 
    geekName = gName; 
} 
@end 
// ------------------------------------------------------------------------ ** 

回答

8

閱讀memory management rules。 9個簡單的段落,解釋你需要知道的一切。

因爲geekName不是以「alloc」或「new」開頭或包含「copy」,所以它應該返回一個你沒有「擁有」的字符串。因此,您不需要(也不一定)釋放它,而且您也不得存儲對它的引用。您可以從您所在的方法中返回它,在這種情況下,您的方法名稱也不應以「alloc」或「new」開頭或包含「copy」。

如果你想保留它,你必須通過調用retain來取得它的所有權,或者因爲它的NSString更好是複製。如果將其分配給複製/保留屬性,這可能是自動的。

在您現在發佈的代碼中,您在setter中發生了錯誤。您的二傳手應該採取的輸入參數的副本,是這樣的:

- (void)setGeekName:(NSString*)gName { 
    if (geekName != gName) { 
     [geekName release]; 
     geekName = [gName copy]; 
} 

那麼你還需要一個dealloc的程序,釋放geekName:

- (void) dealloc 
{ 
    [geekName release]; 
    [super dealloc]; 
} 

或者,您可以使用目標C屬性。相反,你的界面顯示的:

- (NSString*) geekName; 
- (void) setGeekName:(NSString*)gName; 

使用屬性:

@property (nonatomic, copy) NSString* geekName; 

,而是你的getter和setter方法的實施,讓系統將它們合成爲您提供:

@synthesize geekName; 

你仍然需要dealloc方法來釋放geekName。

2

這將取決於你如何擁有屬性 「geekName」 成立。我會假設它只是返回對類中現有成員的引用而不是創建副本?如果是這樣的話,你不需要擔心在你的代碼中發佈任何東西。

您應該只需要擔心在dealloc中釋放「geekName」成員()爲類是在。

+0

我明白了,我的課堂界面如下,所以你說的是什麼,我真的應該有一個dealloc方法的,因爲該班A [geekName釋放];我在想,如果我發佈了planetClass對象時,它可能會被釋放(即[newPlanet_01發行]) @interface PlanetClass:NSObject的{ \t浮法比重; \t浮動質量; \t的char *名稱; \t NSString * geekName; \t } Cheers gary – fuzzygoat 2009-08-27 14:18:03

+0

@fuzzygoat - 取決於您最初如何分配該字符串。如果你使用了alloc()或類似的東西,你需要釋放它。如果你從一個靜態的「帶引號的字符串」分配它,那麼它不需要被釋放。 – 2009-08-27 14:37:18

0

變量都是免費的。局部變量由編譯器爲您分配;實例變量由運行時分配爲實例的一部分。

您在變量中放置指針的對象不是空閒的;你可能需要釋放它們。是否需要釋放物體由the rules決定。

0

根據你如何使用兩個局部變量,你可能需要更多的內存管理。

您的代碼讀取方式是將局部變量設置爲由兩個類對象返回的指針。如果您已經正確編寫了newPlanet*類,那麼在釋放類時應該釋放字符串對象。如果你的兩個局部變量,然後嘗試使用指針,你就會有問題,因爲對象不再療法

兩種可能的更正:

1.保留字符串明確

由於局部變量被直接分配,你應該真正保留的對象明確:

planet_01_Geek = [[newPlanet_01 geekName] copy]; 
planet_02_Geek = [[newPlanet_02 geekName] copy]; 

我在這裏指定副本,因爲這是保持保持的首選方式的對象可能是可變的,否則如果原來的變化,局部變量也會改變。

2.使用特性(優選的)

這將是我優選的方法:所述retaincopy,或assign對於實例變量然後由類處理。

正確聲明的屬性,即:

@property (nonatomic, copy) NSString *planet_01_Geek; 
@property (nonatomic, copy) NSString *planet_02_Geek; 

使用@synthesize在執行。

然後使用屬性語法來分配變量。

self.planet_01_Geek = [newPlanet_01 geekName]; 
self.planet_02_Geek = [newPlanet_02 geekName]; 

這樣正確的內存管理規則將適用於分配和合成的訪問器方法也將釋放當前分配給本地變量的任何對象的照顧。

編輯 - 顯示

在你setGeekName:方法您正在泄漏內存,因爲另外一類的細節的說明。當你爲本地變量分配一個新的指針時,你並沒有將一個版本發送給原來在那裏的對象。一個更好的辦法來做到這一點(使用retain而不是copy保持簡單:

- (void)setGeekName:(NSString *)gName { 
    [gName retain]; // Hold on to the object that is passed in. 
    [geekname release]; // Let go of your current object. 
    geekName = gName; // Now allocate the new object. 
} 
+0

嗨,Abizern,我只是縮減了代碼(它只是早期學習的東西),並在上面完整地發佈了它。我現在只是在閱讀你的回覆,非常感謝。 – fuzzygoat 2009-08-27 15:09:45

+0

我剛剛開始(上週是準確的),我知道@synthesize和屬性,但還沒有得到儘可能看,我認爲他們在第9章,我仍然在3 :) – fuzzygoat 2009-08-27 16:08:27

+0

沒關係;當你到達那個部分時記住這一點。 – Abizern 2009-08-27 16:17:35