我知道如果你做了以下事情,你肯定会有内存泄漏:
id foo = [[NSObject alloc] init];
foo = nil;
但是,如果你使用self.foo,一个带保留的属性怎么办?而您的代码如下所示:
foo = [[NSObject alloc] init];
self.foo = nil;
这仍然是内存泄漏,因为访问者在将内存设置为nil之前先释放内存吗?
答案 0 :(得分:4)
self.foo = nil
会转化为
[nil retain]
[foo release]
foo = nil
此处没有内存泄漏。
答案 1 :(得分:2)
不,第二个例子不是内存泄漏。实际上,这就是我在retain
方法中处理dealloc
属性的方式。它只是更清洁了。
唯一需要注意的是确保不写
self.foo = [[NSObject alloc] init];
否则你将双重保留对象并最终导致内存泄漏。
答案 2 :(得分:1)
属性使您的代码看起来像赋值,但实际上它们与您在Obj-C 2.0之前编写的传统访问器方法相同。使用属性Obj-C只是为您生成幕后的访问器方法,而不是使用您在声明中指定的关键字(假设您使用@synthesize而不是编写自己的访问器方法)。
答案 3 :(得分:1)
不,没有内存泄漏。第二个示例中的代码在逻辑上等同于
foo = [[NSObject alloc] init];
[nil retain];
[foo release];
foo = nil;
因为@synthesized setter的逻辑等价于
- (void)setFoo:(id)newFoo {
[newFoo retain];
[foo release];
foo = newFoo;
}
值得注意的是,直接设置foo
可能不是你想在init方法之外做的事情。如果您直接为foo
分配值,则会绕过自动KVO通知(您必须将您的作业包装在willChangeValueForKey:/didChangeValueForKey:
对中)和中断任何子类的行为如果它覆盖setFoo:
方法,则期望foo
的所有修改都通过设置器。
您在init方法中直接分配给foo
,因为setFoo:
方法或子类'overriden setFoo:
方法可能有副作用或依赖于实例的完全初始化。
同样,出于同样的原因,您可以在[foo release]
方法中使用self.foo = nil;
而不是-dealloc
。
答案 4 :(得分:1)
到目前为止,所有答案都假设第二个示例第一行中的“foo
”是foo
属性后面的实例变量。这是默认行为。
如果第一行指定的foo
是局部变量,那么foo
属性是无关紧要的,除非您稍后在方法中释放它,否则您将泄漏该对象。
如果foo
是一个实例变量,但foo
属性实际上是由另一个实例变量支持,或者根本没有实例变量,那么(a)你写的是难以维护的代码和(b)可能是泄密。
最后,回显前面的答案:如果foo
是支持foo
属性的实例变量,那么这不是泄漏,因为您在第二个调用的setFoo:
方法line将释放您放在第一行foo
实例变量中的对象。
答案 5 :(得分:0)
我不这么认为,通过做self.foo = nil
你实际上是在使用setter并免费获得内存管理。
答案 6 :(得分:0)
由于其他人似乎没有注意到: 可能泄漏。
我假设foo
既是ivar又是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;