方法参数不需要__bridge?

Posted

技术标签:

【中文标题】方法参数不需要__bridge?【英文标题】:__bridge not needed for method arguments? 【发布时间】:2014-02-17 03:46:27 【问题描述】:

我们知道,使用 ARC,我们需要 __bridge 来将 id 转换为 void *

void *t = (void *)self;           // ERROR: Cast of ... requires a bridged cast
void *t = (__bridge void *)self;  // CORRECT

C 函数调用也是如此:

void f(void *t) 
  ....


f((void *)self);           // ERROR
f((__bridge void *)self);  // CORRECT

我认为这也应该适用于方法,实际上这个Beginning ARC in ios 5 Tutorial 给出了以下示例,并说需要__bridge

MyClass *myObject = [[MyClass alloc] init];
[UIView beginAnimations:nil context:(__bridge void *)myObject];

但是,今天我不小心在我的一个程序的方法调用中删除了__bridge,并且代码编译并运行没有任何问题。上面示例中的__bridge 似乎是不必要的:

[UIView beginAnimations:nil context:(void *)myObject];  // COMPILED OK

这是对的吗?在这种情况下,__bridge 真的不需要吗?或者删除它会改变代码的含义?

【问题讨论】:

【参考方案1】:

ARC docs section 3.3.3(强调我的)对此进行了介绍:

3.3.3 在某些上下文中从可保留对象指针类型转换

[开始 Apple 4.0,LLVM 3.1]

如果可保留对象指针类型的表达式被显式转换 对于 C 可保留指针类型,程序是不正确的,如所讨论的 除非立即使用结果:

初始化 Objective-C 消息中的参数 参数没有用 cf_consumed 属性标记,或者 在直接调用审计函数时初始化参数,其中 该参数未使用 cf_consumed 属性进行标记。

在您的代码中,myObject 是“可保留对象指针”。 “C 可保留指针类型”包括 void*(这是一个稍微草率的定义,他们将其用作占位符,因为核心基础“对象”通常是 void*)。

因此,如果将 ObjC 对象用作方法参数,则可以将其隐式转换为 void*。在这种情况下,没有额外的内存管理语义(即它相当于__bridge 演员表)。 Section 7.8 警告我们 void* 将来可能不会被这样对待,但我不会担心。如果发生这种情况,添加__bridge 将是微不足道的。

要记住的一件事是myObject 在这里不受保护。您可以确保以其他方式保留它直到动画完成,否则您可能会崩溃。

【讨论】:

非常有趣,而且很有发现。 +1 因为你给了我另一个讨厌 ARC 的理由 ;-)【参考方案2】:

__bridge 用于传递变量/引用的所有权(如保留计数),即 C api 到 Objective-C 或 Objective-C 到 API。

通过Clang's doc:

桥接演员表

桥接转换是用三个关键字之一注释的 C 样式转换:

(__bridge T) op casts the operand to the destination type T. If T is a retainable object pointer type, then op must have a

不可保留的指针类型。如果 T 是不可保留的指针类型, 那么 op 必须有一个可保留的对象指针类型。否则演员表 格式不正确。没有所有权转移,ARC插入没有 保留操作。 (__bridge_retained T) op 将必须具有可保留对象指针类型的操作数强制转换为目标类型,该目标类型必须是 不可保留的指针类型。 ARC 保留价值,但须遵守 通常对局部值进行优化,接收者负责 为了平衡+1。 (__bridge_transfer T) op 将必须具有不可保留指针类型的操作数强制转换为目标类型,该目标类型必须是 可保留对象指针类型。 ARC 会在最后释放值 封闭的完整表达式,服从通常的优化 当地价值观。

需要这些转换才能将对象移入和移出 电弧控制;参见关于转换的部分的基本原理 可保留的对象指针。

纯粹使用 __bridge_retained 或 __bridge_transfer 强制转换来说服 ARC分别发出不平衡的保留或释放很差 表格。

现在,

void *t = (void *)self; // 错误:... 的演员表需要桥接演员表 为什么会出错,因为您尝试将引用从 Objective-C 转换为 C。它未能传递引用的所有权。

void *t = (__bridge void *)self; // 正确 为什么它是正确的,因为将您的目标 C 引用转移到 C。根据 LLVM 的文档。请参阅上面给出的铸造规则。

MyClass *myObject = [[MyClass alloc] init];
[UIView beginAnimations:nil context:(__bridge void *)myObject];

以上几行完全没问题,因为您传递的是 C 引用类型上下文而不是 NULL

【讨论】:

以上是关于方法参数不需要__bridge?的主要内容,如果未能解决你的问题,请参考以下文章

百度超级链XChainXVM虚拟机

Jmeter参数化方法

魔术方法 __tostring __debugInfo __call

SpringMVC_[2]处理器参数的获取

SpringMVC_[2]处理器参数的获取

python中类定义的时候没有参数吗