2009-07-13 59 views
5

/自動釋放混亂,我慢慢地自學可可爲iPhone(通過Stanford Class on iTunes U)和我剛剛通過對內存管理的部分走了,我想希望得到一些證實的假設我正在處理如何處理內存以及[釋放]和[autorelease]如何工作。由於內存管理是一個非常基礎且基本的,但非常重要的編程經驗的一部分,我想確保我做對了。釋放可可的iPhone

據我所知,有什麼頁頭,新,或複製需要被釋放。
如果我這樣做:

NSString *temp = [[NSString alloc] initWithString:@"Hello World"]; 

然後我需要添加[臨時發佈/自動釋放]最後,因爲我有一個頁頭。

但是,如果我這樣做:

NSString *temp = @"Hello World"; 

然後,它似乎並不需要釋放的語句。 NSString類是否作爲賦值的一部分自動調用autorelease?

此外,有沒有這些語句後,這裏兩個*臨時對象之間有什麼區別?它們都包含相同的字符串,但它們在哪裏有不同的內存/使用方式?

其次,性能,我假設自動釋放自動處理。如果我有這樣的:

@interface Person : NSObject 
{ 
    //ivars 
    NSString *firstName; 
    NSString *lastName; 
} 

//properties 
@property NSString *firstName; 
@property NSString *lastName; 

///next file 

@implementation Person 

@synthesize firstName; 
@synthesize lastName; 

- (void) dealloc 
{ 

    //HERE!!!! 

    [super dealloc]; 
} 

我假設我並不需要添加[名字發佈]和[姓氏釋放(在//此處!!!!),因爲這是自動的處理性能。那是對的嗎?

我也明白,如果我這樣做的代碼(假設我定義initWithFirstName):

Person *Me = [[Person alloc] initWithFirstName: @"Drew", lastName:"McGhie"]; 

,後來我將不得不使用[我發佈/自動釋放]。

任何確認或修正我的理解迄今幫助是極大的讚賞。

郵政的答案寫了

我以爲會在所有的答案,測試出的建議後,我會寫這一切並談什麼工作。

我需要添加[名字發佈],[姓氏發行],但我還需要(保留)添加到屬性的描述。不添加(保留)導致的警告,因爲它假定(分配)。下面是我終於成立了類

@interface Person : NSObject 
    { 
     //ivars 
     NSString *firstName; 
     NSString *lastName; 
    } 

    //properties 
    @property (retain) NSString *firstName; 
    @property (retain) NSString *lastName; 

    ///next file 

    @implementation Person 

    @synthesize firstName; 
    @synthesize lastName; 

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

回答

10

規則很簡單:如果你有alloccopyretain,這是你的責任release。如果你沒有,那不是。但是,如果您需要依賴留在的物體,則必須retain(和隨後的release)。

我們可以根據規則處理字符串文字 - 您不需要release它,因爲您不擁有它。這很簡單;沒有必要擔心他們是否是特殊情況,只要遵守規則,你就會好起來的。

我寫了一篇博文,收集了articles about the Cocoa memory management rules;我建議跟進一些參考。

1

最後部分第一條:您確實將有自動/釋放Me。但是,您還必須在-dealloc中添加[firstName release];[lastName release];;或更好; self.firstName = nil;

至於字符串文字;這部分有點毛,但[@"String literal" release]實質上是一個noop。因此,這兩個臨時對象之間的區別,但是因爲您通常不會知道要處理哪個對象,所以添加了[temp release];通常是安全的選擇,除非你知道它會包含一個自動釋放的對象。

+0

我沒有明確地分配/復​​制/保留firstName或lastName。這是否需要,因爲alloc是通過綜合自動生成來推斷的,我只是在代碼中看不到? – 2009-07-13 19:12:56

+0

從某種意義上說。問題的關鍵在於你的對象擁有firstName和lastName,所以當它們被設置時,它就成爲你釋放它們的責任。 – 2009-07-13 19:29:02

3
  1. 我從來沒有發佈像NSString *foo = @"x";字符串常量。從邏輯上講,如果你不得不release的結果,你將不得不release參數initWithString,並且這兩個參數也要initWithFirstName:lastName:
  2. 您必須做releaseautoreleasefirstNamelastName。我已經看到了有關在析構函數中不使用屬性語法的警告,我認爲這與在C++構造函數和析構函數中不使用虛函數的原因相同。

你的假設是錯誤的。你必須這樣做要麼這一點:

Person *Me = [[Person alloc] initWithFirstName: @"Drew" 
              lastName: @"McGhie"]; 
    ... 
    [Me release]; 

或本:

Person *Me = [Person personWithFirstName: @"Drew" 
            lastName: @"McGhie"]; 

...,並確保您的Person對象處理+personWithFirstName:lastName:正確,即[[[self alloc] initWithFirstName: firstName lastName: lastName] autorelease]

你應該做一個代碼較少的人。清晰度很重要,NSAutoreleasePool可能永遠不會成爲你的瓶頸,如果它永遠是它很容易修復。

我認爲人們付出了很多努力,以避免返回autorelease'd對象,這是不合適的類消息。這是過早的優化,因爲它可能不是必要的,甚至可能不是正確的做法。而且難以維持,你很可能會永遠追逐泄漏。

而且,你要autorelease一個對象,你必須init(即alloc + initPersonWithFirstName:lastName:,而不是使用像personWithFirstName:lastName:一類的消息),我建議你馬上去做。否則,你可能會追逐同樣的泄漏。所以,如果你不打算到personWithFirstName:lastName:方法添加到Person,而是執行此操作:

Person *Me = [[[Person alloc] initWithFirstName: @"Drew" 
              lastName: @"McGhie"] autorelease]; 

摘要:可可做了很多幫助您與內存管理。確保你不打架。

根據Jon在評論中的反饋進行了更新。

+0

而不是[[[個人分配] initWithFirstName:名字姓氏:姓氏] autorelease],[[[自我分配] initWithFirstName:名字姓氏:姓氏] autorelease]會更合適。通過使用self,您將分配正確類型的對象,即存在人員子類。例如:[SpecialPerson personWithFirstName:@「Drew」lastName:@「McGhie」]將正確實例化一個特殊的人。 在「+」方法中,self指擁有該方法的類。 – 2009-07-13 20:48:57

1

關於firstname/lastName。

爲清楚起見,您應該始終記住指定屬性的屬性。設置者的默認屬性是,指定爲,在這種情況下您要使用保留

@interface Person : NSObject 
{ 
    NSString *firstName; 
} 
@property (retain) NSString *firstName; 
@end 

隨着保持每個只有一次使用點符號賦值編譯器插入一個保留:只記得總是使用它。爲了保持一致性我建議你寫你的初始化是這樣的:

- (id) initWithFirstName:(NSString*) aString 
{ 
    self.firstName = aString; 
} 

和dealloc方法是這樣的:

- (void) dealloc 
{ 
    self.firstName = nil; 
} 

關於@ 「」 - 類型的對象。它們是不變的NSStrings對象。只要使用它們(它們是)NSString對象並從不釋放它們。編譯器會照顧它們。

1

NSString類是否作爲賦值的一部分自動調用autorelease?

NSString類沒有做任何事情,因爲你沒有發送消息。你所做的只是分配給一個變量。 NSString沒有發現這個,它不是它的業務。

另外,這些陳述後面的兩個* temp對象之間是否有區別?它們都包含相同的字符串,但它們在哪裏有不同的內存/使用方式?

它們都是NSStrings,它們都包含相同的值,並且它們都被假定爲不可變的。這就是你應該關心的一切。

其次,有了屬性,我假設自動釋放是自動處理的。如果我有這樣的:

@property NSString *firstName; 
@property NSString *lastName; 

- (void) dealloc 
{ 
    //HERE!!!! 

    [super dealloc]; 
} 

我假設我不需要添加[firstName release][lastName release](在//HERE!!!!),因爲這是自動的屬性來處理。那是對的嗎?

編號NSObject不會爲您釋放所有的屬性值;你仍然需要在那裏釋放它們。

此外,不要做self.firstName = nilself.lastName = nildealloc。這些轉換成消息(到你的訪問器方法),當你在dealloc中這樣做時,你發送消息給一個半對象。這是在惹麻煩。在init中用同樣的方法來初始化屬性值:使用你的屬性/訪問器將會發送消息到一半的對象。

2

使用@"String here"語法創建的NSString是常量字符串。這些與普通字符串不同。就像普通的C常量字符串一樣,它們是在程序加載並存在的整個生命週期中創建的。它們所屬的NXConstantString類將忽略所有內存管理消息。你可以retainrelease他們所有你喜歡的,它不會有任何區別。

對於使用[[NSString alloc] initWith...]類型方法創建的字符串,應用正常的memory management rules。我強烈建議閱讀鏈接的文檔 - 它們並不複雜,閱讀完後,您幾乎可以知道有關Cocoa內存管理的所有知識。