【问题标题】:__bridge not needed for method arguments?方法参数不需要__bridge?
【发布时间】: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 真的不需要吗?或者删除它会改变代码的含义?

【问题讨论】:

    标签: ios objective-c automatic-ref-counting 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

    【讨论】:

      猜你喜欢
      • 2020-09-02
      • 1970-01-01
      • 2015-10-04
      • 2014-10-24
      • 2013-08-19
      • 1970-01-01
      • 2012-11-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多