使用retain / autorelease混淆了内存管理

时间:2012-11-01 23:13:00

标签: objective-c memory-management retain foundation

假设我有以下代码:

@property (nonatomic, retain) *SomeObject foo;
@property (nonatomic, retain) *SomeObject bar;

@synthesize foo, bar;

self.foo = [[SomeObject alloc] init];
self.bar = [[[SomeObject alloc] init] autorelease];

if (self.foo) {
    [self.foo release];
    self.foo = nil;
}

if (self.bar) {
    [self.bar release];
    self.bar = nil;
}

我的self.bar出现内存泄漏。我不确定为什么,但我认为这是因为在调用[self.bar release]之后,对象self.bar指向自动释放。当我把self.bar排除在外时,我们尝试在前一个对象(已经自动释放)上调用release,这会产生错误。它是否正确?还有,其他内存泄漏,也许与foo? 什么是正确的解决方案?

我应该删除发布语句并且只删除这两个属性吗?

2 个答案:

答案 0 :(得分:2)

您应该直接使用访问者:

self.foo = [[[SomeObject alloc] init] autorelease];
self.bar = [[[SomeObject alloc] init] autorelease];

if (self.foo) {
    self.foo = nil;
}

if (self.bar) {
    self.bar = nil;
}

因为合成属性访问器生成执行引用计数操作的代码。

永远不要使用[someObject.someProperty release]格式。

你不应该使用访问器的唯一地方是部分构造的状态(即初始化和dealloc)。在此上下文中,使用直接访问:[ivar release], ivar = nil;

答案 1 :(得分:1)

您的代码中有3个地方错误:

@property (nonatomic, retain) *SomeObject foo;
@property (nonatomic, retain) *SomeObject bar;

self.foo = [[SomeObject alloc] init]; // WRONG 1
self.bar = [[[SomeObject alloc] init] autorelease];

if (self.foo) {
    [self.foo release]; // WRONG 2
    self.foo = nil;
}

if (self.bar) {
    [self.bar release]; // WRONG 3
    self.bar = nil;
}

在任何方法中,除非直接在对象上设置实例变量,否则必须平衡保留和释放。您没有直接在此处设置任何实例变量。您正在使用属性(方法调用)。

1是错误的,因为alloc返回一个保留实例(你(这个方法)“拥有”它,因此你必须在它超出你的范围之前释放它)。您将它传递给方法(属性设置器),然后您不再具有对它的引用。因此它被泄露了。

2和3是错误的,因为你发布的是你不拥有的东西。属性访问是方法调用,普通方法调用不返回保留实例。

错误1和2碰巧平衡 - 有很多错误,他们碰巧以错误的方式取得了正确的结果。错误3应该导致程序崩溃,因为你过度释放。