我正在使用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
)?
答案 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,但这无关紧要。)