64

我有一些關於Objective-C中合成屬性的問題。完整列表如下,但基本問題是這樣的:即使我的代碼可能包含或不包含dealloc中的發佈方法,編譯器如何確保合成屬性的ivars被正確釋放?@synthesized retain屬性如何處理髮布?

注:我決定不發佈這些個別問題,因爲他們是如此密切相關,因爲有現存的問題了一把該在個別問題上的觸摸沒有真正得到到問題的心臟。

有點類似的問題:


設置:考慮一類具有一個屬性:

@interface Person : NSObject 
{ 
    NSString * name; 
} 
@property (nonatomic, retain) name; 
@end 

問題1:非常基本情況:

@implementation Person 
@synthesize name; 
@end 

在此設置下,我認爲name將每當Person對象被釋放被自動釋放。在我看來,編譯器只是簡單地將[name release]插入到dealloc方法中,就好像我自己輸入了一樣。那是對的嗎?


問題2:如果我選擇寫我自己的dealloc方法這個類,我忽略到[name release]一個電話,就會把漏?

@implementation Person 
@synthesize name; 
- (void)dealloc { [super dealloc]; } 
@end 

問題3:如果我選擇寫我自己的dealloc方法這個類,我包括[name release]一個電話,將這一結果在雙釋放,因爲@synthesize已經爲我照顧過了嗎?

@implementation Person 
@synthesize name; 
- (void)dealloc { [name release]; [super dealloc]; } 
@end 

問題4:如果我選擇寫這個類我自己的屬性訪問,但我寫我自己的dealloc方法,將name被泄露?

@implementation Person 
@dynamic name; 
- (void)setName:(NSString *)newName 
{ 
    [newName retain]; 
    [name release]; 
    name = newName; 
} 
@end 

問題5:我有一種感覺,(根據經驗)認爲上述情況沒有會導致泄漏或雙版本,因爲該語言的設計是爲了避免他們。當然,這提出了「如何?」的問題。編譯器是否足夠聰明以跟蹤每一個可能的情況?如果我是做到以下幾點(注意,這是一個可笑的例子,只是爲了說明我的觀點):

void Cleanup(id object) { [object release]; } 

@implementation Person 
@synthesize name; 
- (void)dealloc { Cleanup(name); } 
@end 

將這種欺騙編譯器爲增加另一個[name release]dealloc方法?

回答

57

Q1:

@synthesize號不修改-dealloc你。你必須自己-releasename

Q2:

是的,它會泄漏。與Q1相同的原因。

Q3:

沒有也不會雙重釋放。與Q1相同的原因。

Q4:

是的,它會泄漏。與Q1相同的原因。

Q5:

沒有也不會雙重釋放。與Q1相同的原因。


您可以通過覆蓋-retain-release-dealloc報告是怎麼回事,這個檢查自己。

#import <Foundation/Foundation.h> 

@interface X : NSObject {} 
@end 
@implementation X 
-(oneway void)release { 
     NSLog(@"Releasing %p, next count = %d", self, [self retainCount]-1); 
     [super release]; 
} 
-(id)retain { 
     NSLog(@"Retaining %p, next count = %d", self, [self retainCount]+1); 
     return [super retain]; 
} 
-(void)dealloc { 
     NSLog(@"Dealloc %p", self); 
     [super dealloc]; 
} 
@end 

@interface Y : NSObject { 
     X* x; 
} 
@property (nonatomic, retain) X* x; 
@end 
@implementation Y 
@synthesize x; 
- (void)dealloc { [x release]; [super dealloc]; } 
@end 

int main() { 
     NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; 
     Y* y = [[Y alloc] init]; 
     X* x = [[X alloc] init]; 
     y.x = x; 
     [y release]; 
     [x release]; 
     [pool drain];              
     return 0; 
} 

在Q1,Q2和Q4的x最後-retainCount爲1,所以存在泄漏,並且在Q3和Q5的最後-retainCount是0和-dealloc被調用,所以沒有泄漏。

+2

謝謝你的詳細解答。我很高興我問過! – 2010-02-03 06:27:07

+0

非常好解釋! – 2013-05-01 11:41:22

17

Objective-C documentation on properties

的dealloc

聲明的屬性從根本上採取 存取方法 聲明的地點;當您合成 屬性時,編譯器僅創建任何缺少訪問器方法的 。有 與dealloc沒有直接交互 方法 - 屬性不是 自動爲您發佈。 聲明的屬性做,不過, 提供了一個有用的方式交叉檢查 您的dealloc 方法的實現:你可以看看所有的 屬性聲明在頭 文件,並確保對象 屬性沒有標記分配是 發佈,那些標記爲分配的是 未發佈。

這基本上回答你所有的問題。

+0

+1謝謝你的鏈接。這當然是問題的核心。 – 2010-02-03 06:26:21

8

簡單和一般規則:如果您分配,保留或複製一個對象,您必須將其釋放。

當您在@synthesize語句中使用retain設置語義設置時,您要求編譯器爲您構建一個設置對象的調用retain的設置器。沒有更多,沒有更多。並且由於您保留了該對象(即使它是通過神奇的自動生成的代碼),您必須將其釋放,並將其釋放到-(void)dealloc

+4

+1這是一個很好的(和經常參考的)規則。許多人(包括我在內,當我問這個問題時)沒有意識到在屬性聲明中指定「保留」或「複製」仍然有資格。我認爲問題在於措辭:「我*保留了價值嗎?不,編譯器的自動代碼爲我做了這件事,糟糕。」 – 2010-12-21 15:09:43

+1

發佈這個答案几個月後,我發佈了一個更好的,在這裏:http://stackoverflow.com/questions/5122786/iphone-objective-c-should-this-value-be-released/5122821#5122821 它有一個很好的助記符。去看。 – 2011-09-12 15:56:08

+0

好東西。我希望它抓住! – 2011-09-12 16:24:57

2

其他值得知道 - 如果你有一個綜合屬性,將該屬性設置爲零(當然使用點語法)會爲你釋放伊娃。