代码之家  ›  专栏  ›  技术社区  ›  mipadi

如何修复此clang警告:“带有+0保留计数的对象返回给调用方,其中需要+1(拥有)保留计数”?

  •  10
  • mipadi  · 技术社区  · 14 年前

    我有一段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行分配并存储到“path”中的对象的潜在泄漏

    带有+0保留计数的对象返回给调用方,其中需要+1(拥有)保留计数

    我搞糊涂了。我的理解是 stringByAppendingPathComponent 应该返回一个自动释放的字符串,因此 应该 净保留计数为0。(显然我没有 希望 保留它。

    我试过改变 copyData: 返回以下内容,但没有消除警告:

    return [[path retain] autorelease];
    

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

    5 回复  |  直到 13 年前
        1
  •  15
  •   Ben Zotto    14 年前

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

    当然,在您的案例中,您指的是文件和其他内容,所以这是一个不可忽略的警告。如果您将方法的名称更改为 saveData: 相反,我打赌警告会消失。

        2
  •  9
  •   Jason Coco    14 年前

    此外,有时您确实想用“copy”或其他名称命名方法,因为不管cocoa内存管理准则如何,copy是该方法的最佳名称,您可以用 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;
    
        3
  •  4
  •   Dave DeLong    14 年前

    因为该方法具有名称 copy 在它中,分析器期望返回的对象具有+1保留计数,根据 Memory Management Guide .

        4
  •  4
  •   Michael Aaron Safyan    14 年前

    不,这是不正确的;除非方法包含“alloc”、“copy”、“new”或暗示该对象将由调用程序拥有的其他关键字之一,否则该方法将返回自动租用或其他托管对象,因此StringByAppendingPathComponent将返回自动租用字符串。

    除此之外,您的方法“copydata”包含单词“copy”,这意味着结果应该由调用方拥有(和发布)。但是,您返回的结果是自动释放的,因此它会向您发送错误消息。如果要修复错误,请不要自动释放。即:

     return [path retain]
    

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

    “copydata”这个名字,imho,无论如何都是非故意的。我建议您将函数重命名为“pathtosavedatawithdata”或类似的名称。说它实际上在做什么的东西。

        5
  •  0
  •   hkatz    13 年前

    我想尝试一下,你会得到同样的错误信息,不管你的程序名是否以“copy…”开头。我刚刚在一个类似的场景中结束,“复制”并不是我所调用的例程的名称。Clang给出错误消息仅仅是因为我返回了一个自动释放的对象,这是一个危险的情况。做

      return [path retain]  
    

    最后,按照迈克尔的建议,技巧解决了这个问题。