Objective c 方法返回带有+;1保留计数

Objective c 方法返回带有+;1保留计数,objective-c,Objective C,自从升级到Lion并最终升级到XCode 4.1之后 在运行分析器时,我会遇到几十个“潜在内存泄漏” 我通常会使用如下属性列表: @synthesize indexPath = _indexPath; - (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)nibBundle { self = [super initWithNibName:nibName bundle:nibBundle]; self.index

自从升级到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()方法中:

现在,analyze将向我显示self.indepath上可怕的蓝色消息,告诉我有漏洞。显然没有

如何分配和格式化代码,以使XCode不认为代码泄漏?(保留属性别名self.var vs_var)


谢谢你……

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

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

试试这个:

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

在init中,您实际上应该直接使用ivars进行设置:

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

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

静态分析器可能只是在看这一行,因为它不够聪明,无法意识到您实际上是在试图纠正这个问题

我会使用这种模式

NSIndexPath *tmpPath = [[NSIndexPath alloc] init];
self.indexPath = tmpPath;
[tmpPath release];
更深入的解释。因此,当分析仪观察测线时

self.indexPath = [[NSIndexPath alloc] init];
这是该零件的+1保留

[[NSIndexPath alloc] init]
它看到
self.indepath
被编译为

[self setIndexPath:[[NSIndexPath alloc] init]];
此方法(如果由
@synthesis
自动生成)可能如下所示

- (void)setIndexPathL(NSIndexPath *)indexPath
{
    if (_indexPath != indexPath) {
        [_indexPath release];
        _indexPath = [indexPath retain];
    }
}
现在,分析器看到在indexath上还有另一个
retain


这就是2x+1retain,它只能假设您将在dealloc中释放一次。

问题是,通过使用setter方法,编译器无法保证您传递给setter的同一对象将实际分配给支持ivar。毕竟,setter方法可能会做各种奇怪的事情,其中至少包括复制传递的对象

换句话说,编译器无法保证
self.indepath==\u indepath
,因此对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];

我尝试了各种方法,比如:[self.indepath release];但随后我得到了“调用方此时不拥有的对象的引用计数的错误递减率”。在我的示例中,我展示了一个实例,其中它是一个init方法,但我在我的项目中始终使用此代码结构。正在执行self.var=。。。负责取消分配以前分配的任何实例。这样做_var=[[ClassName alloc]init];这不是一个符合所有人意见的通用方法:下面是我的解决方案:self.var=nil_var=[[ClassName alloc]init];无论上下文如何,这都将以类似的方式工作。
self.var=…
不仅仅用于释放旧值;它还保留/复制并指定新值。如果自动释放从
init
获取的对象,则可以将其直接指定给属性,而无需先将
nil
指定给属性,然后再直接指定给ivar。这使它成为一个单行程序,比你坦率地说奇怪的(最好是超优化的)两行程序清晰得多。作为一个长期的嵌入式开发人员,不让一个对象自动发布对我来说要优雅得多:否则会更慢,而且内存占用效率低下。对不起,我没有注意到。但是这句话可能是在欺骗分析器,所以我将把这个问题作为“常见的替代品”留在这里。正如我在前面的评论中提到的,实际上我正在研究一些足够通用的东西,以便它在init方法中使用相同的编码结构,或者不使用。如果需要,使用self.var将负责释放任何内存required@Kendall:我假设分析人员在发布ivar而不是某个局部变量这一事实上遇到了麻烦。它可能不认识到ivar是该属性的支持ivar。@鲁迪:我也这么认为,在这种情况下,它不知道self是self,因为它可以改变…@jyavenard,除了init方法,我同意你的意见,但是在init中,您应该远离访问器,以避免触发KVC检查,也就是说,对象还不能兑现……分析器没有捕获释放的原因是setter方法可能为支持ivar分配了与传递的对象不同的对象。值得注意的是,如果您传递了一个无效的对象,它可能会将支持ivar设置为nil。因此,在您的示例中,
\u indepath
不能保证与
tmpPath
是同一个对象,这就是为什么分析器会对此发出警告。如果属性方法为retain,则这两个对象将始终相同。@jyavenard:假设您没有重写setter方法,则是。假设这不是覆盖setter方法的子类的实例。假设没有人使用setter方法。关键是,编译器不能做出这些假设;它没有在编译时做出保证的信息,这就是为什么您会收到编译时警告,指出可能存在问题。而且,正如您所指出的,如果将属性声明为“copy”而不是“retain”,那么即使仅使用合成setter方法,内存管理也可能不正确。
[self setIndexPath:[[NSIndexPath alloc] init]];
- (void)setIndexPathL(NSIndexPath *)indexPath
{
    if (_indexPath != indexPath) {
        [_indexPath release];
        _indexPath = [indexPath retain];
    }
}
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
_indexPath = [[NSIndexPath alloc] init];