【问题标题】:Passing an object around increases retain count传递一个对象会增加保留计数
【发布时间】:2015-09-25 23:12:10
【问题描述】:

iOS,正在过渡到 ARC。我观察到关于 CF/NS 桥接的奇怪行为。在以下场景中:

CFStringRef cfs = ComesFromSomewhere();
NSString *ns = (__bridge NSString*)cfs;

字符串对象的保留计数最后为 2。但是,在以下方面:

NSString *ToNS(CFStringRef cfs)
{
    return (__bridge NSString*)cfs;
}

CFStringRef cfs = ComesFromSomewhere();
NSString *ns = ToNS(cfs);

最后保留计数为 3。请问这是怎么回事?谁拥有额外的参考?对象是否只是通过传递而被添加到自动释放池中?

对“别担心,ARC 正常工作”的抢先反应:我在这里将 Core Foundation 与 Cocoa 混合在一起,没有办法。这很容易泄漏。如果无法明确说明保留计数,我就瞎了。

编辑:它是调试版本的工件。在release build中,后一种情况下的retain count还是2。

在留下大型自动释放对象的片段和不留下的片段之间存在明显的区别;您不希望前者在循环体中没有池的大循环中。有助于了解它是零优化的产物,但仍然不酷。

【问题讨论】:

  • 你有调试手表或变量上的其他东西吗?这可能会使变量保持活动状态,您可以对其进行检查。
  • 不考虑差异。该函数没有引入额外的变量,没有什么可看的。
  • 仪器工具 leaks 在这种情况下可能会有所帮助,尽管有时这就像大海捞针一样。
  • 没有泄漏,我已经检查过了。它真的看起来像一个隐藏的保留/自动释放。但我更喜欢确认。
  • “如果无法明确说明保留计数,我就瞎了眼。”如果您使用静态分析器,则不会。它会告诉你是否对内存管理不善。

标签: ios automatic-ref-counting


【解决方案1】:
CFStringRef cfs = ComesFromSomewhere();

// retainCount -> 1

NSString *ns = ToNS(cfs);

// ToNS(cfs)
//
// ToNS is not object creating method,
// thus the returned object was automatically autoreleased
// retainCount += 1

// NSString *ns
// 
// It's __strong variable, ns variable has an ownership of the object
// retainCount += 1

// retainCount -> 3

object creating method 的定义是一个名称以“alloc”、“new”、“copy”或“mutableCopy”开头的 Objective-C 类的方法。见Basic Memory Management Rules - You own any object you create

在release构建中,后一种场景下的retain count还是2。

如果对象符合条件,编译器也可以省略向对象发送自动释放消息。

已编辑

您可以使用 C++ 引用来避免自动释放。

void ToNS(CFStringRef cfs, NSString __strong *& ns)
{
    ns = (__bridge NSString*)cfs;
}

NSString *nsstr;
ToNS(cfstr, nsstr);

// retainCount -> 2

已编辑

NS_RETURNS_RETAINED NSString *ToNS(CFStringRef cfs)
{
    return (__bridge NSString*)cfs;
}

NS_RETURNS_RETAINED 使框架将函数视为创建对象的对象(确实如此)。 Cocoa 有一个命名约定,允许您将方法指定为对象创建者,但该约定仅适用于 Objective C 类方法,不适用于 C 样式函数,也不适用于 C++ 类成员函数。

【讨论】:

  • 所以没有办法将 C/C++ 函数指定为创建对象的对象,而不是包装在静态类方法中?
  • 更新了我避免自动释放的答案。
  • 看起来 ns_returns_retained 属性也可以解决问题...让我测试一下。
  • 经过测试,使用 NS_RETURNS_RETAINED 进行注释将计数减少到 2。只有您必须将属性放在返回类型之前的前导位置。已编辑。
猜你喜欢
  • 2014-12-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多