桥接演员:__ bridge_transfer vs __bridge with synthesis setter

时间:2013-01-16 06:26:04

标签: objective-c automatic-ref-counting

我正在使用ARC,并在使用__bridge_transfer时感到困惑。我有一个属性userName如下:

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

案例 1

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 会发生什么?我应该在CASE 2 中使用__bridge还是不应该使用CASE 2 ?在案例 2 __bridge_transfer__bridge,如何平衡引用计数?

在CASE 2 中,__bridge_transfer,ARC将释放对象(该对象,作为参数传递给setter (void)setUserName:(NSString *)userName)?

3 个答案:

答案 0 :(得分:20)

当您致电ABRecordCopyCompositeName()时,某人必须在某个时候释放返回的对象。使用__bridge_transfer可确保ARC为您释放对象。如果没有__bridge_transfer,则必须手动释放返回的对象。这是唯一的两个选择。

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

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

答案 1 :(得分:3)

案例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.
}

案例2:

-(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,它返回对非托管对象(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.

答案 2 :(得分:1)

正是因为这令人困惑,我建议您分别使用CFBridgingRelease()CFBridgingRetain(),而不是使用__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属性的setter的实现者管理它。 (在这种情况下恰好也是ARC,但这无关紧要。)