【问题标题】:How can I fix this clang warning: "Object with +0 retain counts returned to caller where +1 (owning) retain count is expected"?如何解决此 clang 警告:“返回 +0 保留计数的对象返回到预期 +1(拥有)保留计数的调用者”?
【发布时间】:2011-02-19 17:48:38
【问题描述】:

我有一段 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];

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

【问题讨论】:

    标签: objective-c cocoa clang clang-static-analyzer


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

      另外,当你真的想用'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】:

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

      【讨论】:

        【解决方案4】:

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

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

         return [path retain]
        

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

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

        【讨论】:

          【解决方案5】:

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

            return [path retain]  
          

          Michael 推荐的最后技巧解决了这个问题。

          【讨论】:

          • 哎呀!我可以评论我自己的答案吗?原来我的例程名称以“new ...”开头,所以看起来我有点仓促。我现在更清楚了。 :-)
          猜你喜欢
          • 2011-04-02
          • 1970-01-01
          • 2023-03-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-03-19
          • 2011-06-05
          相关资源
          最近更新 更多