11

我正在使用 ARC,并且在使用__bridge_transfer. 我有一个属性userName如下:

@property (nonatomic, retain) NSString *userName;
...
@synthesize userName = _userName;
...

案例

NSString *name = (__bridge_transfer NSString *)ABRecordCopyCompositeName(person);
self.userName = name;

案例2

self.userName = (__bridge_transfer NSString *)ABRecordCopyCompositeName(person);

哪里person是类型ABRecordRef

在 CASE 1中,ARC 会释放局部变量名(根据我的理解,如果我错了,请纠正我),但是在 CASE 2中会发生什么?我应该__bridge在 CASE 2中使用还是CASE 2根本不应该使用?在使用or的情况2中,如何平衡引用计数?__bridge_transfer__bridge

在 CASE 2中,使用__bridge_transferARC 是否会释放对象(该对象,作为参数传递给 setter (void)setUserName:(NSString *)userName)?

4

3 回答 3

22

当您调用 时ABRecordCopyCompositeName(),必须有人在某个时候释放返回的对象。使用__bridge_transfer确保 ARC 将为您释放对象。没有__bridge_transfer,您必须手动释放返回的对象。这是仅有的两个选择。

因此,您必须__bridge_transfer在这两种情况下都使用。

一个很好的练习是通过使用__bridge而不是诱导泄漏__bridge_transfer,然后使用 Xcode 和 Instruments 来尝试找到泄漏。编译器会发现泄漏吗?静态分析(项目 -> 分析)是否会发现泄漏?Instruments 是否会发现泄漏?如果是这样,您将知道如何检查是否__bridge_transfer解决了问题。

于 2013-01-16T07:09:43.000 回答
4

案例 1 和案例 2 是等价的。可以这样想:

情况1:

-(void)func {
  NSString *name = someObject;  // Retain, so +1 on the reference count
  self.userName = name;         // Retain, so +1 on the reference count
  // End of function, name is going out of scope,
  // so release name, so -1 on the reference count.
  // Total change to the reference count: +1 for self.userName.
}

案例二:

-(void)func {
  self.userName = someObject;   // Retain, so +1 on the reference count
  // End of function.
  // Total change to the reference count: +1 for self.userName.
}

所以他们的工作是一样的。请注意,如果这样做是安全的,则允许编译器取消保留和释放对。在像这样的简单情况下,它肯定会忽略它们。考虑对引用计数的所有 +1 和 -1 更改只是为了使其更清晰。

要回答有关 __bridge 与 __bridge_transfer 的问题:您调用ABRecordCopyCompositeName了 ,它返回对非托管对象 (a CFStringRef) 的引用。函数名中的Copy告诉你这个对象现在归你所有,你最终需要释放它。

您可以致电 来完成此操作CFRelease,也可以让 ARC 为您完成此操作。 __bridge告诉 ARC 它不允许拥有所有权(换句话说,您想手动释放该对象,或者它不归您所有)。 __bridge_transfer告诉 ARC 它应该获得所有权并在完整表达式的末尾释放对象(换句话说,您要求 ARC 为您进行释放)。

__bridge_transfer

self.userName = (__bridge_transfer NSString *)ABRecordCopyCompositeName(person);  // +1 inside ABRecordCopyCompositeName, +1 for self.userName, -1 at the end, because of the __bridge_transfer.
// self.userName now is the only strong reference.  Good.

__bridge

CFStringRef userName = ABRecordCopyCompositeName(person);  // +1 inside ABRecordCopyCompositeName.
self.userName = (__bridge NSString *)userName;             // +1 for self.userName, ARC does nothing because of the __bridge.
CFRelease(userName);                                       // -1.
// self.userName now is the only strong reference.  Good.

__bridge和内存泄漏:

self.userName = (__bridge NSString *)ABRecordCopyCompositeName(person);  // +1 inside ABRecordCopyCompositeName, +1 for self.userName, ARC does nothing because of the __bridge.
// self.userName now is one strong reference, but reference count is 2.
// Memory leak.
于 2015-02-13T08:27:29.887 回答
1

正是因为这令人困惑,我建议您分别使用CFBridgingRelease()andCFBridgingRetain()而不是使用 and 进行强制__bridge_transfer转换__bridge_retained。然后,您需要记住的唯一“不寻常”演员表是__bridge,它与所有权无关。

我发现它更容易记住,因为类似这样的东西ABRecordCopyCompositeName()让您CFRelease()对返回的对象负责,您可以使用它CFBridgingRelease()来履行该责任,并且类比是显而易见的。

同样,您只能在对象指针已经是 Core Foundation 类型时使用CFBridgingRetain()的上下文中使用。CFRetain()

因此,您的代码可能是:

NSString *name = CFBridgingRelease(ABRecordCopyCompositeName(person));
self.userName = name;

或者:

self.userName = CFBridgingRelease(ABRecordCopyCompositeName(person));

在这两种情况下,CFBridgingRelease()函数Copy名称中的 都表示您有责任释放对象。在那之后,这都是别人的责任。ARC 管理name变量。属性设置器的实现者userName管理它。(在这种情况下也恰好是 ARC,但这无关紧要。)

于 2015-09-11T02:25:58.957 回答