2009-04-16 32 views
2

我知道,如果你做下面的你肯定有內存泄漏:這是一個objective-c內存泄漏嗎?

id foo = [[NSObject alloc] init]; 
foo = nil; 

但是,如果你使用的是什麼self.foo,有一個屬性保留?而你的代碼,而不是看起來如下:

foo = [[NSObject alloc] init]; 
self.foo = nil; 

是仍然由於訪問內存泄漏將其設置爲nil前先釋放內存?

回答

4

self.foo = nil將轉化爲

[nil retain] 
[foo release] 
foo = nil 

沒有內存泄漏在這裏。

2

不,第二個例子不是內存泄漏。實際上,這就是我在dealloc方法中處理retain屬性的方法。它只是更清潔。

你必須要小心的就是製作出的唯一的事情一定不要寫

self.foo = [[NSObject alloc] init]; 

,否則你會雙保留了對象,並使用了內存泄漏而告終。

+4

請記住,使用dealloc中的屬性通常會阻止訪問方法更改爲修改另一個ivar(可能已被釋放)的情況。我只是使用發佈。 – 2009-04-16 16:42:37

0

我不這麼認爲做self.foo = nil你基本上是使用setter和獲得內存管理一起免費。

1

屬性使你的代碼看起來像賦值,但實際上它們與Obj-C 2.0之前自己寫的傳統存取器方法相同。使用屬性Obj-C只是在後臺爲你生成訪問器方法,而不是使用聲明中指定的關鍵字(假設你使用@synthesize並且不要編寫自己的訪問器方法)。

1

不,沒有內存泄漏。在第二個例子中的代碼在邏輯上等同於

foo = [[NSObject alloc] init]; 
[nil retain]; 
[foo release]; 
foo = nil; 

因爲@synthesized二傳手是logicall相當於

- (void)setFoo:(id)newFoo { 
    [newFoo retain]; 
    [foo release]; 
    foo = newFoo; 
} 

值得一提的是,設置foo直接可能不是你想要的外面做些什麼一個init方法。如果你直接把值賦給foo,你跳過自動志願的通知(你將不得不包裝你的任務在willChangeValueForKey:/didChangeValueForKey:對)你打破任何的子類的行爲,如果它覆蓋setFoo:方法,期待的foo所有修改通過二傳手。

您可以直接在init方法分配給foo因爲重寫setFoo:方法可能有副作用或取決於實例setFoo:方法或子類的完全初始化。

同樣,由於相同的原因,您將在-dealloc方法中使用[foo release]而不是self.foo = nil;

1

到目前爲止的所有答案都假定第二個示例的第一行中的「foo」是foo屬性後面的實例變量。這是默認行爲。

如果foo第一行指定的是局部變量,那麼foo屬性是無關緊要的,除非稍後在方法中釋放它,否則將泄漏該對象。

如果foo是一個實例變量,但foo財產實際上是由不同的實例變量的支持,或沒有實例變量的話,那麼(一)你正在編寫難以維護的代碼和(b)可以是泄漏。

最後,呼應以前的答案:如果foo是實例變量後盾foo屬性,那麼這是不是泄漏,因爲setFoo:方法,你在第二行調用將釋放對象,你把foo第一行中的實例變量。

0

由於沒有人似乎已經注意到:還有可能是有泄漏。

我假設foo既是伊娃和retain屬性:

@interface Foo : NSObject { 
    NSObject * foo; 
} 
@property (nonatomic, retain) NSObject * foo; 
@end 

比方說,你的代碼看起來是這樣的:

-(void)bar { 
    foo = [[NSObject alloc] init]; 
    self.foo = nil; 
} 

也就是說,本身不漏提供foo爲零,以開頭。這並不意味着它不會泄露 - 假設你添加一些代碼:

-(void)baz { 
    self.foo = [[NSObject new] autorelease]; 
} 

-(void)fubar { 
    [self baz]; 
    [self bar]; 
} 

foo = [[Foo alloc] init]的東西,因爲它是假設你只叫他們的一個通常是init - 方法安全,所以foo是最初保證爲nil。在其他地方,你必須更加小心。

// Use assertions so it crashes debug builds if it's already set 
assert(!foo); 
foo = [[NSObject alloc] init]; 
self.foo = nil; 

// Or release explicitly. 
[foo release]; 
foo = [[NSObject alloc] init]; 
self.foo = nil; 

// Or just use the setter, which will do the "right thing". 
// This is particularly relevant for "copy" or "assign" accessors. 
self.foo = [[[NSObject alloc] init] autorelease]; 
self.foo = nil;