【问题标题】:Clang: what is "Method returns an Objective-C object with a +0 retain count" trying to tell me?Clang:什么是“方法返回具有 +0 保留计数的 Objective-C 对象”试图告诉我?
【发布时间】:2023-03-26 18:51:01
【问题描述】:

在 XCode 3.2 和 Nikita Zhuk's Analysis Tool 中使用 clang 运行静态分析我经常遇到这对警告:

方法返回一个具有 +0 保留计数(非拥有引用)的 Objective-C 对象

调用者此时不拥有对象的引用计数的错误递减

可能引发此警告的代码示例:

UIButton* button = [[UIButton buttonWithType:UIButtonTypeCustom] initWithFrame: CGRectMake(x, y, width, height)];
return button;

我假设以这种方式创建的按钮是自动释放的,就像使用便利工厂方法创建的任何其他 NSObject 一样。所以我返回它,调用者可以决定是否保留它。这有什么问题?

我是否有义务在返回对象之前保留并自动释放它? 最重要的是,这个警告所警告的东西是否会成为与发布相关的可怕崩溃的原因?

我现在意识到这似乎只发生在 UIButtons 上。是不是因为是类簇?

编辑:下面的片段显示了 clang 发出这些警告的最小情况(警告以粗体显示)。在创建对象的语句(buttonWithType: 消息)上标记了两个警告。

-(UIButton*) ztupidTezt:(UIImage*) img
{
  UIButton* bt = [[UIButton buttonWithType:UIButtonTypeCustom]initWithFrame:

1 方法返回一个具有 +0 保留计数(非拥有引用)的 Objective-C 对象

2 调用者此时不拥有对象引用计数的错误递减

    CGRectMake(0.0f, 0.0f, img.size.width, img.size.height)];
    bt setImage:img forState:UIControlStateNormal];
    return bt;
}

【问题讨论】:

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


    【解决方案1】:

    嗯....那个代码没有意义。

    buttonWithType: 返回一个已初始化的 UIButton 实例。你不应该打电话给-initWithFrame:。

    致电setFrame:。

    错误的代码使分析器感到困惑。

    其次,为什么要使用第三方工具进行分析。如果您在 Snow Leopard 上使用 Xcode 3.2(您应该是——它是 Xcode 的一个比 Leopard 上的最后一个版本好得多的版本),您可以只“构建和分析”。所有的分析结果都将很好地与您的代码一起呈现。

    【讨论】:

    • 谢谢。与我对 outis 的评论中相同的附加问题适用。 “分析器困惑”是对无用警告消息的一种可能解释。其次,我仍然主要使用XCode3.1,因为我仍然主要使用Leopard。分析工具会在 clang 的基础上为您提供额外的建议和警告(有些有用,有些可能不太有用)。
    • 我不确定分析器是否感到困惑。 buttonWithType: 返回一个自动释放的(+0 保留计数)对象,这正是分析器所说的正在发生的事情。你没有说什么语句得到了标志#4;我猜这是您没有向我们显示的 release 或 autorelease 消息。
    • 不,没有释放或自动释放消息。 (如果有,我可能会经常遇到崩溃。)为了在此处获得最佳答案,我尽我所能向您展示所有可能相关的内容。请参阅添加到原始问题的最小示例案例。
    • 我仍然想知道的是,这段公认的错误代码真的会导致崩溃吗?
    • 当然——在已经初始化的对象上调用 -init* 的行为是未定义的。
    【解决方案2】:

    原因很可能是同时发送buttonWithType: 和initWithFrame: 消息。 init* 方法执行对给定对象只应执行一次的任务。创建对象的类方法也会初始化它们。您的代码的结果是重复初始化。而是发送buttonWithType 消息,然后分配给frame 属性。

    【讨论】:

    • 有道理,我会听从你的建议。但是您解释的内容如何反映在 clang 发出的警告消息中?实际上是否存在错误减少保留计数的危险?我不能说我注意到任何似乎与此相关的错误(但这当然可能是因为它们刚刚经过我的雷达)。
    • 这需要比我拥有更多的 Clang 和 Objective-C 内部知识。如果我不得不猜测,我会说“+0 保留计数”是指对buttonWithType: 的调用,而init*: 消息应该只发送到拥有的对象,因此发送initWithFrame: 会引发警告。翻译,buttonWithType: 错误地减少了保留计数,因为initwithFrame: 需要一个拥有的对象。
    • outis:关闭。 initWithFrame: 消息是错误的,但没有考虑到任何一个分析器警告。
    【解决方案3】:

    包含此代码的方法名称是否以“new”作为前缀? Clang 静态分析器遵循标准 Cocoa 命名约定,并假定 -newSomething 方法将返回一个保留计数为 1 的实例。如果它看到从此类方法返回的自动释放对象,它可能会显示您看到的警告。

    【讨论】:

    • 不,它没有。请参阅上面添加的最小示例。
    【解决方案4】:

    老,老,问题。我有同样的问题。我认为现有的答案成功地解释了为什么代码是错误的,以及为什么分析器说“+0 保留计数”。但是,似乎没有人解释为什么分析器说代码正在减少保留计数。我想我知道为什么了。这是因为如何允许 init 方法返回与您发送消息的对象不同的对象。他们会释放原始对象,分配一个新对象,然后返回它。分析器假设任何 init 方法都可以做这样的事情,尽管本例中的 init 方法可能不会。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-02-19
      • 1970-01-01
      • 2011-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-04-19
      相关资源
      最近更新 更多