10

我有一段 Objective-C 代码,如下所示:

- (NSString *)copyData:(NSData *)data
{
    NSString *path = [[[self outputDirectory] stringByAppendingPathComponent:@"archive"] stringByAppendingPathExtension:@"zip"];
    NSLog(@"Copying data to %@", path);
    [data writeToFile:path atomically:NO];
    return path;
}

代码从如下所示的初始化程序调用:

- (id)initWithData:(NSData *)data
{
    if ((self = [super init]) != nil) {
        NSString *path = [self copyData:data];        // Line 41 (referenced in warning, shown below)
        return [self initWithContentsOfFile:path];
    }
    return self;
}

运行 clang 静态分析器时,我收到以下path变量警告:

在第 41 行分配并存储到“路径”中的对象的潜在泄漏

具有 +0 保留计数的对象返回给调用者,其中预期 +1(拥有)保留计数

我很困惑。我的理解是stringByAppendingPathComponent应该返回一个自动释放的字符串,所以它的净保留计数应该是 0。(显然我不想保留它。)

我尝试更改copyData:以返回以下内容,但并没有消除警告:

return [[path retain] autorelease];

那么这个警告是怎么回事呢?

4

5 回答 5

15

我怀疑它只是注意到一个带有前缀的方法并将其copy标记为应该返回调用者拥有的东西,因为它认为它遵循 Cocoa 命名约定。

当然,就您而言,您指的是文件之类的东西,因此这是一个可忽略的警告。如果您将方法的名称更改为类似的名称saveData:,我敢打赌警告会消失。

于 2010-05-14T22:05:06.843 回答
9

此外,对于您确实想用“复制”或其他名称命名方法的时候,因为不管 Cocoa 内存管理指南如何,复制是该方法的最佳名称,您可以使用NS_RETURNS_NOT_RETAINED然后 Clang注释方法声明你一个警告。所以:

// Copies data from data to string; does not follow the copy rule
- (NSString*)copyData:(NSData*)data NS_RETURNS_NOT_RETAINED;
于 2010-08-06T17:55:06.627 回答
4

根据Memory Management Guide ,由于该方法中包含名称copy,因此分析器期望返回的对象具有 +1 保留计数。

于 2010-05-14T22:06:34.217 回答
4

不,这是不正确的;除非该方法包含“alloc”、“copy”、“new”或暗示对象将由调用者拥有的其他关键字之一,否则该方法返回一个自动释放或以其他方式管理的对象,因此 stringByAppendingPathComponent 返回一个自动释放的字符串.

最重要的是,您的方法“copyData”包含单词“copy”,这意味着结果应该由调用者拥有(和释放)。但是,您返回的结果已被自动释放,因此它给您的错误消息。如果要修复错误,请不要自动释放。那是:

 return [path retain]

当然,这意味着您的函数的调用者需要释放它。或者,您可以更改函数的名称,使其符合内存管理准则。

恕我直言,名称“copyData”无论如何都是不直观的。我建议您将函数重命名为“pathToSavedDataWithData”等。说明它实际上在做什么的东西。

于 2010-05-14T22:14:30.830 回答
0

我将对此进行尝试,并猜测您会收到相同的错误消息,无论您的例程名称是否以“复制...”开头。我刚刚遇到了类似的情况,并且“复制”不是我正在调用的例程名称的一部分。Clang 给出错误消息仅仅是因为我返回了一个自动释放的对象,这是一种危险的情况。做

  return [path retain]  

迈克尔推荐的最后技巧解决了这个问题。

于 2011-02-19T19:12:04.893 回答