返回给调用者的对象保留计数为+0,而预期是+1(拥有)保留计数。

6
我有一组由www.sudzc.com创建的类(这是一个很棒的WDSL Web服务代理创建工具,适用于iPhone / Flex / JavaScript)。
当我运行CMD + SHIFT + A检查内存泄漏时,我会收到以下消息:

返回了带有+0保留计数的对象给调用者,但预期需要+1(拥有)保留计数

这是它返回该消息的方法:
// Static method for initializing from a node.
+ (id) newWithNode: (CXMLNode*) node
{
    return (id)[[[SoapObject alloc] initWithNode: node] autorelease];
}

我不想使用这段代码进行消息传递,因为在项目中需要多次重新生成它,随着网络服务的更改,我需要更新代理类。

有什么好的建议吗?

提前致谢。

Jason

3个回答

12
分析器报错是因为内存管理指南规定:使用以“alloc”或“new”开头或包含“copy”的方法创建对象。Cocoa和Objective-C的约定俗成非常重要,你应该尽力遵循它们。打开“将警告视为错误”选项并修复问题。虽然你可能是唯一的开发者,但如果其他开发者在任何时候使用你的方法,则他们可能会遵循内存管理指南,并过度释放此方法返回的对象(导致应用程序崩溃)。

这是完全正确的。如果你想返回一个自动释放的对象,那么请重命名该函数。你可以尝试使用 +createWithNode: 代替。否则,去掉自动释放并依赖调用者来自动释放它。 - Lily Ballard
嗨,Jerry/Kevin,感谢这些信息。非常感谢!根据Jerry的推荐,我进行了全局搜索和替换newWithNode,并用createWithNode代替它。我重新编译了一下,一切都正常。现在,每当我使用http://www.sudzc.com wsdl生成工具生成更新的代理类集时,我需要记得这样做。再次感谢! - JasonBub

5

这个方法被标记是因为它的方法名有'new'前缀。静态分析器只是在评论,应用普通的方法命名惯例,人们期望该方法返回一个需要释放而不是自动释放的对象。

像这样的方法的“正常”命名约定是以类的名称作为前缀,例如如果该方法是为名为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, 谢谢您的回复!非常感谢!最终我改变了方法的名称。谢谢! Jason - JasonBub

0
如果您有一个必须包含"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)这样的东西,它基于名称中的“copy”错误地触发了警告。 - Lily Ballard
嗨,肯德尔,感谢您提供关于如何调整LLVM的优秀信息。这真的很酷。我最终改变了方法名。但是,我也会尝试将此方法用于我的内部知识库。再次感谢! 杰森 - JasonBub
@Kevin - 我说过名字必须要有new或copy时,是在这个情境下。你正在谈论从描述服务器端调用的WSDL生成的方法名称,通常作为服务的消费者,你无法重命名这些方法。但我同意,如果可能的话,这样的方法名称对Objective-C程序员来说会非常困惑!因此,我会将其包装在其他应用程序中使用的其他调用中。 - Kendall Helmstetter Gelner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接