【问题标题】:Do I have to autorelease this object?我必须自动释放这个对象吗?
【发布时间】:2009-08-16 14:45:33
【问题描述】:

我正在使用 -initWithObjectsAndKeys 创建一个 NSDictionary:。

对于我提供给该字典的每个对象,我都会调用一个自制方法 -createFooBarObject,它将创建并返回该对象。

现在的问题:根据定义,create 方法不应该释放对象,因为它必须返回它,并且调用者负责释放它。但是在这里,调用者没有机会释放它,因为 NSDictionary 立即将其吸入。我在 -initWithObjectsAndKeys: 对象和键列表中调用该创建方法,因此在添加到字典后我没有机会调用 -release。好吧,我可以遍历字典并将它们全部释放。但这很丑。

那么在 -createFooBarObject 方法返回之前 -autorelease 是否有效?我不确定-autorelease 会在什么时候发生。但它不应该在字典创建并保留该对象之前发生。有什么想法吗?

【问题讨论】:

  • 发布一段代码会得到一个更具体的答案。

标签: objective-c cocoa cocoa-touch memory-management


【解决方案1】:

如果您调用 +alloc 来创建对象(您似乎是),那么您必须释放或自动释放。

如果您创建的方法返回使用 +alloc 创建的对象,则必须返回 -autoreleased 对象。

另一种方法是不按照设计模式所说的去做,然后处理您的不同模式以及它们之间的阻抗不匹配。除非性能分析表明您存在只能通过这样做才能解决的性能问题,否则不要去那里。

在这种情况下,您可能希望返回一个 -autoreleased 对象。这样调用者就不必担心调用-release 或-autorelease。这是应该的。

【解决方案2】:

对于 Objective-C API,“new”表示 +1 引用返回值。对于 CoreFoundation,“创建”可以。反之则不成立:“create”和“new”不可互换。

所以在 Objective-C 中,“createFooBarObject”表示一个自动释放的对象,根据当前的规则,你应该自动释放它。如果您确实打算返回 +1 引用对象,则应在名称中使用“new”而不是“create”。

这些规则由clang static analyzer检查。

clang-sa 还允许您通过 attribute((ns_returns_retained)) 或 attribute((cf_returns_retained) )。例如,如果 ObjC 方法通过“create”返回一个新的 CF 对象(如 QuartzCore -[CIContext createCGImage:fromRect:]),则会出现极端情况。如果您有这样的 API,并且 clang-sa 误解了您的意图,您可以注释该方法以明确您确实返回具有特定引用类型的对象。

【讨论】:

  • 现在我很困惑。我从苹果文档中得到它,“create”和 new 都必须返回调用者负责释放的 +1 引用。你从哪里得到这些信息?想阅读更多关于它的信息。感谢 Clang 的提示,我认为这是一个非常有用的东西!
  • @IRTFM:我在内存管理文档中找不到说明您所声称内容的参考。但是,出于这个原因,我通常会尽量避免重述内存管理规则:当规范的规则列表真的很容易访问时,很容易错误陈述并引起混乱。
  • 为 Cocoa 对象返回 +1 ref 的名称列在此处developer.apple.com/iphone/library/documentation/Cocoa/… 的文档中。
【解决方案3】:

两个注意事项:你用 alloc 创建一个对象,你用 initWithObjectsAndKeys 初始化它——alloc/init 总是成对的,所以它通常只是技术上的区别。

但更重要的是,创建方法应该返回一个拥有的对象,你应该自动释放它。这在memory management rules 中明确指定。鉴于该规范以及将方法命名为“create”导致的混乱,我建议不要在方法名称中使用“create”,而是将其称为 fooBarObject 并返回一个自动释放(或其他无主)对象。如果您这样做,那么您的问题会立即自行解决。

那么在 -createFooBarObject 方法返回之前 -autorelease 是否有效?

这不仅是有效的,而且是绝对必要的——如果您要自动释放的对象在那时归您所有(即,您可以合法地调用 release)。

我不确定 -autorelease 会在什么时候发生。

自动释放池在概念上非常简单 - 系统保留指向对象的指针的副本,当自动释放池耗尽/释放时,它会将释放方法发送给对象。

自动释放池是嵌套的,永远不会意外地被神奇地耗尽——当控制流返回给创建自动释放池的人并释放它时,它们就会被耗尽,这通常是最初调用您的代码来处理事件。

但即使是这种理解在很大程度上也无关紧要 - 只需阅读 memory management rules 并遵守这些规则,您就不会遇到任何问题。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-12-15
    • 1970-01-01
    • 1970-01-01
    • 2012-07-06
    • 1970-01-01
    • 1970-01-01
    • 2011-02-15
    • 2019-08-20
    相关资源
    最近更新 更多