2009-04-16 47 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;