【问题标题】:Object with +0 retain counts returned to caller where a +1 (owning) retaincount is expected具有 +0 保留计数的对象返回给调用者,其中预期 +1(拥有)保留计数
【发布时间】:2011-04-02 23:25:53
【问题描述】:

我有一组由 www.sudzc.com 创建的类(用于 iPhone/Flex/Javascript 的很棒的 WDSL Web 服务代理创建工具)。

当我运行 CMD+SHIFT+A 来检查内存泄漏时,我收到以下消息:

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

这是返回该消息的方法:

// Static method for initializing from a node.
+ (id) newWithNode: (CXMLNode*) node
{
    return (id)[[[SoapObject alloc] initWithNode: node] autorelease];
}

我不想使用此代码发送消息,它需要通过项目多次重新生成,因为 Web 服务发生变化,我需要更新代理类。

有什么想法吗?

提前致谢。

杰森

【问题讨论】:

    标签: iphone memory-leaks


    【解决方案1】:

    如果您的方法名称中必须包含“new”或“copy”之类的内容,并且您知道警告无效 - 您可以通过向 LLVM 包含该类确实正常的提示来消除警告.

    在你的头文件中,首先添加这个(通常在顶部附近,但它可以在任何地方):

    #ifndef __has_feature      // Optional.
    #define __has_feature(x) 0 // Compatibility with non-clang compilers.
    #endif
    
    #ifndef NS_RETURNS_NOT_RETAINED
    #if __has_feature(attribute_ns_returns_not_retained)
    #define NS_RETURNS_NOT_RETAINED __attribute__((ns_returns_not_retained))
    #else
    #define NS_RETURNS_NOT_RETAINED
    #endif
    #endif
    

    然后在方法声明的末尾添加如下:

    + (id) newWithNode: (CXMLNode*) node NS_RETURNS_NOT_RETAINED;
    

    您可以在此处找到可以传递给 LLVM 的其他提示(真正的属性)列表:

    http://clang-analyzer.llvm.org/annotations.html

    【讨论】:

    • 你当然可以这样做,但是它会让其他看到这段代码的人感到困惑,因为他们会假设一个名为 +newWithNode: 的方法应该返回一个拥有的对象。这个技巧对于诸如 -dataNoCopyForColumn: (取自 FMDB)之类的东西更有用,它会根据名称中的“复制”错误地触发警告。
    • 您好 Kendall,感谢您提供有关如何调整 LLVM 的出色信息。这真的很酷。我最终更改了方法名称。但是,也会为我的内部知识库尝试这种方法。再次感谢!杰森
    • @Kevin - 我确实说过什么时候必须有新的或复制的名称 - 在这种情况下,您正在谈论从描述服务器端调用的 WSDL 生成的方法名称,而您通常没有作为该服务的消费者重命名方法的权力。但我同意,如果可能的话,像这样的方法名称会让 objc 程序员非常困惑!如此之多,以至于我将其包装在应用程序中所有其他代码都使用的其他调用中。
    【解决方案2】:

    分析器在抱怨,因为memory management guide 表明...

    您使用名称以“alloc”或“new”开头或包含“copy”'的方法“创建”一个对象。

    Cocoa 和 Objective-C 严重依赖约定,您应该尽一切努力遵循它。打开“将警告视为错误”并修复问题。虽然您现在可能是唯一一个从事此工作的人,但如果在任何时候其他开发人员要使用您的方法,他们很可能会遵循内存管理指南,并最终过度释放此方法返回的对象(并崩溃应用程序)。

    【讨论】:

    • 这完全正确。如果要返回自动释放的对象,请重命名该函数。你可以试试+createWithNode:。否则,摆脱那个自动释放并依赖调用者来自动释放它。
    • 嗨,Jerry/Kevin,感谢您提供此信息。值得赞赏!根据 Jerry 的建议,我对 newWithNode 进行了全局搜索和替换,并将其替换为 createWithNode。我重新编译,一切正常。现在,每当我使用sudzc.com wsdl 生成工具生成一组更新的代理类时,我都需要记住这样做。再次感谢!
    【解决方案3】:

    该方法被标记,因为该方法名称具有“新”前缀。静态分析器只是在评论应用正常的方法命名约定,人们会期望该方法返回您打算释放的对象,而不是自动释放的对象。

    方法的“正常”命名约定是在方法前面加上类的名称,例如,如果该方法是为名为 Widget 的类定义的:

    @interface Widget : NSObject {
    }
    + (id)widgetWithNode:(CXMLNode*)node; // Returns an object that has been autoreleased.
    - (id)initWithNode:(CXMLNode*)node; // Returns an object you are expected to release.
    @end
    

    如果您正确使用该方法(也就是说,您正在考虑它返回自动释放对象的事实),那么您可以忽略该警告。

    【讨论】:

    • 嗨 Imaginaryboy,感谢您的回复!值得赞赏!我最终更改了方法的名称。谢谢!杰森
    猜你喜欢
    • 1970-01-01
    • 2011-02-19
    • 1970-01-01
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    • 2012-01-13
    • 1970-01-01
    相关资源
    最近更新 更多