2011-08-31 70 views
17

有人告訴我一個fellow StackOverflow user該釋放特性時,我不應該使用的getter方法:爲什麼我不應該使用getter來釋放objective-c中的屬性?

@property(nonatmic, retain) Type* variable; 
@synthesize variable; 

// wrong 
[self.variable release]; 

// right 
[variable release]; 

他沒有詳細解釋原因。他們對我來說看起來是一樣的。 My iOS book說對屬性的getter看起來就像這樣:

- (id)variable { 
    return variable; 
} 

所以並不這是否意味着[self variable]self.variablevariable都是一樣的嗎?

+0

這是一個非常危險的建議;吸氣劑並不總是這樣。事實上,如果這是一個「原子」屬性,它會保留/ -autorelease。 – bbum

回答

4

一個典型的getter看起來更像是這樣的:

- (id)variable { 
    return [[variable retain] autorelease]; 
} 

所以如果你使用[self.variable release]你有一個額外的retainautorelease,你並不真正需要時,你只是要釋放的對象和事業要釋放的對象超過必要時(當自動釋放池被耗盡時)。

通常情況下,你要麼使用self.variable = nil它有它也將變量設置爲nil(避免由於懸擺指針崩潰),或[variable release]這是最快的,並可能是,如果你的二傳手在dealloc方法更合適的利益有定製邏輯。

9

您可以選擇編寫自定義getter行爲,這可能會導致完全不同的行爲。所以,你不能總是假設[variable release][self.variable release]有相同的結果。

同樣,你可以在沒有獨家ivar支持的情況下編寫自定義屬性......如果你開始從getters返回的引用中釋放對象,它可能會變得雜亂無章!

self.variable = nil; 

這樣做的效果:

有可能是我不知道的其他原因......

+0

這是真的,但我不能想象什麼樣的getter會改變屬性的方式,用戶將無法釋放它。) – Eimantas

+1

@Eimantas:然而,我不能說,你是釋放對象通過獲取者在你的dealloc中...寫在自定義getter中的代碼可能試圖訪問已經發布的其他ivars,導致崩潰。或者其他奇怪的情況! – MechEthan

+3

也許getter可能會返回一個autoreleased副本?這將是一個可怕的想法,但它仍然是有效的。然後,在這種情況下,釋放getter返回的值會通過過度釋放對象來使程序崩潰。 –

13

對於沒有自定義訪問一個保留的性質,可以通過釋放對象設置ivar(如果您只聲明瞭屬性,可能不會將其稱爲「變量」)設爲零並釋放先前的值。

正如其他人所指出的,無論是直接釋放伊娃(如果可用)或使用上述方法都可以 - 您不能做的就是調用釋放從getter返回的變量。

+0

我知道我在我的回答中忘記了一些重要的東西... upvoted你的,因爲它是一個重要的事情要了解! – MechEthan

+0

我讀了[多個地方](http://stackoverflow.com/questions/5737312/set-to-nil-in-viewdidunload-but-release-in-dealloc/5737438#5737438)屬性應該在' dealloc'並在'viewDidUnload'中設置爲nil。 – JoJo

+1

如果你還有伊娃,你可以直接發佈這個。關鍵是你不能釋放從getter返回的內容,因爲這不能保證是真正的底層變量。直接釋放ivar會阻止執行器中的任何自定義邏輯被執行,如果沒有任何邏輯,則幾乎沒有區別。 – jrturton

4

不是所有的getter採取這種形式:

- (id)variable { return variable; } 

...這僅僅是最原始的形式。單獨屬性應該建議更多的組合,這會改變實施。上面的原始訪問器沒有考慮與內存管理,原子性或複製語義結合使用的習語。在子類覆蓋中實現也很脆弱。

接下來是一些非常簡短的例子;在實現變得相當複雜的實際程序中事情顯然變得更加複雜。

1)getter可能不會返回實例變量。以下幾種可能性之一:

- (NSObject *)a { return [[a copy] autorelease]; } 

2)setter可能不保留實例變量。以下幾種可能性之一:

- (void)setA:(NSObject *)arg 
{ 
    ... 
    a = [arg copy]; 
    ... 
} 

3)您最終在整個程序中實施了內存管理,這使得難以維護。類的語義(以及如何處理實例變量裁判計數)應保持到類,並按照約定的預計業績:

- (void)stuff:(NSString *)arg 
{ 
    const bool TheRightWay = false; 
    if (TheRightWay) { 
     NSMutableString * string = [arg mutableCopy]; 
     [string appendString:@"2"]; 
     self.a = string; 
     [string release]; 
     // - or - 
     NSMutableString * string = [[arg mutableCopy] autorelase]; 
     [string appendString:@"2"]; 
     self.a = string; 
    } 
    else { 
     NSMutableString * string = [arg mutableCopy]; 
     [string appendString:@"2"]; 
     self.a = string; 
     [self.a release]; 
    } 
} 

沒有遵守這些簡單的規則,使你的代碼難以維護和調試和痛苦的擴展。

所以它的缺點是,你想讓你的程序容易維護。直接在一個屬性上調用release會要求你瞭解這個類的內部運作的很多背景;這顯然很糟糕,錯過了很好的OOD理想。

它也期望作者/子類/客戶確切地知道班級是如何偏離約定的,當問題出現時這很愚蠢和耗時,當問題出現時你必須重新學習所有內部細節(他們會在某個時間點)。

這些是一些簡單的例子,說明如何調用釋放屬性的結果引入問題。許多現實世界的問題都更加微妙和難以定位。

相關問題