首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >桥接铸造:__bridge_transfer与__bridge的合成

桥接铸造:__bridge_transfer与__bridge的合成
EN

Stack Overflow用户
提问于 2013-01-16 06:26:03
回答 3查看 10.3K关注 0票数 11

我正在使用ARC,并且在使用__bridge_transfer时有混淆。我有一个属性userName如下:

代码语言:javascript
运行
复制
@property (nonatomic, retain) NSString *userName;
...
@synthesize userName = _userName;
...

病例1

代码语言:javascript
运行
复制
NSString *name = (__bridge_transfer NSString *)ABRecordCopyCompositeName(person);
self.userName = name;

案例2

代码语言:javascript
运行
复制
self.userName = (__bridge_transfer NSString *)ABRecordCopyCompositeName(person);

其中person的类型为ABRecordRef

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

如果2__bridge_transfer一起,__bridge_transfer会释放对象(对象作为参数传递给setter (void)setUserName:(NSString *)userName)吗?

EN

回答 3

Stack Overflow用户

发布于 2013-01-16 07:09:43

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

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

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

票数 22
EN

Stack Overflow用户

发布于 2015-02-13 08:27:29

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

案例1:

代码语言:javascript
运行
复制
-(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:

代码语言:javascript
运行
复制
-(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

代码语言:javascript
运行
复制
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

代码语言:javascript
运行
复制
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和内存泄漏:

代码语言:javascript
运行
复制
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.
票数 4
EN

Stack Overflow用户

发布于 2015-09-11 02:25:58

正因为这令人困惑,我建议您使用CFBridgingRelease()CFBridgingRetain(),而不是分别对__bridge_transfer__bridge_retained进行强制转换。然后,您需要记住的唯一“不寻常”的类型是__bridge,它对所有权没有任何作用。

我发现它更容易记住,因为像ABRecordCopyCompositeName()这样的东西留给您返回对象CFRelease()的责任,您可以使用CFBridgingRelease()来履行这个责任,这种类比是显而易见的。

类似地,如果对象指针已经是Core类型,则只在上下文中使用CFBridgingRetain()

所以,您的代码可能是:

代码语言:javascript
运行
复制
NSString *name = CFBridgingRelease(ABRecordCopyCompositeName(person));
self.userName = name;

或者:

代码语言:javascript
运行
复制
self.userName = CFBridgingRelease(ABRecordCopyCompositeName(person));

在这两种情况下,CFBridgingRelease()在函数名中平衡了Copy,这意味着您有责任释放对象。在那之后,一切都是别人的责任。弧管理name变量。userName属性的setter的实现者对此进行管理。(在这种情况下,碰巧也是ARC,但这与此无关。)

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14352494

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档