方法返回具有+1保留计数的Objective-C对象

时间:2011-07-30 23:36:31

标签: objective-c

升级到Lion并因此升级到XCode 4.1

运行分析仪时,我得到了数十个“潜在的内存泄漏”。

我通常会使用如下属性列表:

@synthesize indexPath = _indexPath;

- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle {
    self = [super initWithNibName:nibName bundle:nibBundle];
    self.indexPath = [[NSIndexPath alloc] init];
    [_indexPath release];
    return self;
}

和dealloc()方法:

- (void)dealloc {
    [_indexPath release];
    [super dealloc];
}

现在,分析会告诉我self.indexPath上可怕的蓝色消息,告诉我有泄漏。什么时候显然没有。

如何分配和格式化代码,以便XCode不相信它会泄漏? (同时保留属性别名self.var vs _var)

谢谢...

5 个答案:

答案 0 :(得分:8)

其他答案已经深入解释了这个问题,无论如何,这些是一些常用的模式可以用来避免这个错误:

NSIndexPath *ip = [[NSIndexPath alloc] init];
self.indexPath = ip;
/* ... */
[ip release];

indexPath = [[NSIndexPath alloc] init];

self.indexPath = [[[NSIndexPath alloc] init] autorelease];

self.indexPath = [NSIndexPath indexPathWithIndex:...];

答案 1 :(得分:6)

在init中你真的应该使用ivars直接设置:

- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle {
    self = [super initWithNibName:nibName bundle:nibBundle];
    _indexPath = [[NSIndexPath alloc] init];
    return self;
}

或许这可以解决这个问题?它将遵循惯例。

答案 2 :(得分:4)

问题在于,通过使用setter方法,编译器无法保证传递给setter的同一对象实际上将被分配给支持ivar。毕竟,你的setter方法可能会做各种奇怪的事情,其中​​最少的可能包括制作传递对象的副本。

换句话说,编译器无法保证self.indexPath == _indexPath,因此您对release的调用可能与您从init方法获得的对象不同。因此,它会向您发出警告,指出您的内存管理可能不正确,这是合适的。

因此,您需要保证在传递给setter的同一对象上调用release。简而言之:

NSIndexPath *tmpPath = [[NSIndexPath alloc] init];
self.indexPath = tmpPath;

[tmpPath release];           // This is the only correct way to do it.
// [self.indexPath release]; // WRONG! May not be the same object as tmpPath
// [_indexPath release];     // WRONG! May not be the same object as tmpPath

正如其他人提到的那样,在init方法中,通常最好直接分配给ivar。因此:

_indexPath = [[NSIndexPath alloc] init];

答案 3 :(得分:2)

试试这个:

NSIndexPath *tmpPath = [[NSIndexPath alloc] init];
self.indexPath = tmpPath;
[tmpPath release];

答案 4 :(得分:2)

静态分析器可能只是在查看那一行,因为它不够聪明,没有意识到你实际上正试图纠正这个问题。

我会使用这种模式

NSIndexPath *tmpPath = [[NSIndexPath alloc] init];
self.indexPath = tmpPath;
[tmpPath release];

更深入的解释。因此,当分析仪查看该行

self.indexPath = [[NSIndexPath alloc] init];

它看到这部分的+1保留

[[NSIndexPath alloc] init]

它看到self.indexPath被编译为

[self setIndexPath:[[NSIndexPath alloc] init]];

此方法(如果由@synthesize自动生成)可能看起来像这样

- (void)setIndexPathL(NSIndexPath *)indexPath
{
    if (_indexPath != indexPath) {
        [_indexPath release];
        _indexPath = [indexPath retain];
    }
}

现在分析器看到indexPath上还有另一个retain

所以这是2 x +1保留,它只能假设您将在dealloc中释放一次。