方法参数不需要__bridge?

时间:2022-09-19 09:13:19

As we know, with ARC we need a __bridge to convert an id to a void *:

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

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

So are C function calls:

C函数调用也是如此:

void f(void *t) {
  ....
}

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

I think this should hold for methods as well, and indeed this Beginning ARC in iOS 5 Tutorial gives the following example, and says that the __bridge is needed:

我认为这也适用于方法,事实上iOS 5 Tutorial中的这个Beginning ARC给出了以下示例,并说需要__bridge:

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

However, today I accidentally dropped a __bridge in a method call in one of my programs, and the code compiled and ran without any issue. The __bridge in the above sample seems to be unnecessary:

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

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

Is this right? Is the __bridge really unnecessary in this case? Or removing it changes what the code means?

这是正确的吗?在这种情况下,__bridge真的没用吗?或者删除它会改变代码的含义?

2 个解决方案

#1


6  

This is covered in the ARC docs section 3.3.3 (emphasis mine):

ARC文档第3.3.3节(强调我的)中对此进行了介绍:

3.3.3 Conversion from retainable object pointer type in certain contexts

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

[beginning Apple 4.0, LLVM 3.1]

[开始Apple 4.0,LLVM 3.1]

If an expression of retainable object pointer type is explicitly cast to a C retainable pointer type, the program is ill-formed as discussed above unless the result is immediately used:

如果将可保留对象指针类型的表达式显式强制转换为C可保留指针类型,则除非立即使用结果,否则程序将如上所述形成错误:

  • to initialize a parameter in an Objective-C message send where the parameter is not marked with the cf_consumed attribute, or to
  • 初始化Objective-C消息中的参数,其中参数未使用cf_consumed属性标记,或者

  • initialize a parameter in a direct call to an audited function where the parameter is not marked with the cf_consumed attribute.
  • 在直接调用审计函数时初始化参数,其中参数未使用cf_consumed属性标记。

In your code, myObject is a "retainable object pointer." A "C retainable pointer type" include void* (this is a slightly sloppy definition that they're using as a placeholder because Core Foundation "objects" are often void*).

在您的代码中,myObject是一个“可保留的对象指针”。 “C可保留指针类型”包括void *(这是一个稍微草率的定义,它们用作占位符,因为Core Foundation“对象”通常是无效的*)。

So an ObjC object can be implicitly converted to a void* if used as a method parameter. In that case, there are no additional memory management semantics (i.e. it is the equivalent of a __bridge cast). Section 7.8 warns us that void* may not be treated this way in the future, but I wouldn't worry about that. If it happens, adding the __bridge will be trivial.

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

The one thing to keep in mind is that myObject is not protected here. It is up to you to make sure it is retained some other way until the animations complete, or you may crash.

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

#2


2  

__bridge is used for passing ownership of variables/references (Like retain count) which is C api to objective-C or objective-C to API.

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

Go through Clang's doc:

通过Clang的文档:

Bridged casts

A bridged cast is a C-style cast annotated with one of three keywords:

桥接演员阵容是使用以下三个关键字之一注释的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

non-retainable pointer type. If T is a non-retainable pointer type, then op must have a retainable object pointer type. Otherwise the cast is ill-formed. There is no transfer of ownership, and ARC inserts no retain operations. (__bridge_retained T) op casts the operand, which must have retainable object pointer type, to the destination type, which must be a non-retainable pointer type. ARC retains the value, subject to the usual optimizations on local values, and the recipient is responsible for balancing that +1. (__bridge_transfer T) op casts the operand, which must have non-retainable pointer type, to the destination type, which must be a retainable object pointer type. ARC will release the value at the end of the enclosing full-expression, subject to the usual optimizations on local values.

不可保留的指针类型。如果T是不可保留的指针类型,则op必须具有可保留的对象指针类型。否则演员阵容不合理。没有所有权转让,ARC不会保留任何保留操作。 (__bridge_retained T)op将必须具有可保持对象指针类型的操作数强制转换为目标类型,该目标类型必须是不可保留的指针类型。 ARC保留该值,取决于对本地值的通常优化,并且接收方负责平衡+1。 (__bridge_transfer T)op将必须具有不可保留指针类型的操作数强制转换为目标类型,该目标类型必须是可保留的对象指针类型。 ARC将在封闭的完整表达式的末尾释放值,这取决于对本地值的通常优化。

These casts are required in order to transfer objects in and out of ARC control; see the rationale in the section on conversion of retainable object pointers.

为了将对象传入和传出ARC控制,需要这些演员表;请参阅有关可保留对象指针转换部分的基本原理。

Using a __bridge_retained or __bridge_transfer cast purely to convince ARC to emit an unbalanced retain or release, respectively, is poor form.

纯粹使用__bridge_retained或__bridge_transfer强制转换来说服ARC分别发出不平衡的保留或释放,这种形式很糟糕。

Now,

void *t = (void *)self; // ERROR: Cast of ... requires a bridged cast Why it wrong because you trying to casting reference from Objective-C to C. It failed to pass ownership of reference.

void * t =(void *)self; // ERROR:Cast of ...需要一个桥接演员为什么它错了,因为你试图将引用从Objective-C转换为C.它未能通过引用的所有权。

void *t = (__bridge void *)self; // CORRECT Why it correct because to transfer your objective-C reference to C. According to doc of LLVM. See above given casting rules.

void * t =(__ bridge void *)self; //正确为什么它正确,因为将您的Objective-C引用转移到C.根据LLVM的文档。见上面给出的铸造规则。

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

Above lines are completely still ok because you pass C reference type context instead of NULL

上面的行完全没问题因为你传递了C引用类型上下文而不是NULL

#1


6  

This is covered in the ARC docs section 3.3.3 (emphasis mine):

ARC文档第3.3.3节(强调我的)中对此进行了介绍:

3.3.3 Conversion from retainable object pointer type in certain contexts

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

[beginning Apple 4.0, LLVM 3.1]

[开始Apple 4.0,LLVM 3.1]

If an expression of retainable object pointer type is explicitly cast to a C retainable pointer type, the program is ill-formed as discussed above unless the result is immediately used:

如果将可保留对象指针类型的表达式显式强制转换为C可保留指针类型,则除非立即使用结果,否则程序将如上所述形成错误:

  • to initialize a parameter in an Objective-C message send where the parameter is not marked with the cf_consumed attribute, or to
  • 初始化Objective-C消息中的参数,其中参数未使用cf_consumed属性标记,或者

  • initialize a parameter in a direct call to an audited function where the parameter is not marked with the cf_consumed attribute.
  • 在直接调用审计函数时初始化参数,其中参数未使用cf_consumed属性标记。

In your code, myObject is a "retainable object pointer." A "C retainable pointer type" include void* (this is a slightly sloppy definition that they're using as a placeholder because Core Foundation "objects" are often void*).

在您的代码中,myObject是一个“可保留的对象指针”。 “C可保留指针类型”包括void *(这是一个稍微草率的定义,它们用作占位符,因为Core Foundation“对象”通常是无效的*)。

So an ObjC object can be implicitly converted to a void* if used as a method parameter. In that case, there are no additional memory management semantics (i.e. it is the equivalent of a __bridge cast). Section 7.8 warns us that void* may not be treated this way in the future, but I wouldn't worry about that. If it happens, adding the __bridge will be trivial.

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

The one thing to keep in mind is that myObject is not protected here. It is up to you to make sure it is retained some other way until the animations complete, or you may crash.

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

#2


2  

__bridge is used for passing ownership of variables/references (Like retain count) which is C api to objective-C or objective-C to API.

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

Go through Clang's doc:

通过Clang的文档:

Bridged casts

A bridged cast is a C-style cast annotated with one of three keywords:

桥接演员阵容是使用以下三个关键字之一注释的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

non-retainable pointer type. If T is a non-retainable pointer type, then op must have a retainable object pointer type. Otherwise the cast is ill-formed. There is no transfer of ownership, and ARC inserts no retain operations. (__bridge_retained T) op casts the operand, which must have retainable object pointer type, to the destination type, which must be a non-retainable pointer type. ARC retains the value, subject to the usual optimizations on local values, and the recipient is responsible for balancing that +1. (__bridge_transfer T) op casts the operand, which must have non-retainable pointer type, to the destination type, which must be a retainable object pointer type. ARC will release the value at the end of the enclosing full-expression, subject to the usual optimizations on local values.

不可保留的指针类型。如果T是不可保留的指针类型,则op必须具有可保留的对象指针类型。否则演员阵容不合理。没有所有权转让,ARC不会保留任何保留操作。 (__bridge_retained T)op将必须具有可保持对象指针类型的操作数强制转换为目标类型,该目标类型必须是不可保留的指针类型。 ARC保留该值,取决于对本地值的通常优化,并且接收方负责平衡+1。 (__bridge_transfer T)op将必须具有不可保留指针类型的操作数强制转换为目标类型,该目标类型必须是可保留的对象指针类型。 ARC将在封闭的完整表达式的末尾释放值,这取决于对本地值的通常优化。

These casts are required in order to transfer objects in and out of ARC control; see the rationale in the section on conversion of retainable object pointers.

为了将对象传入和传出ARC控制,需要这些演员表;请参阅有关可保留对象指针转换部分的基本原理。

Using a __bridge_retained or __bridge_transfer cast purely to convince ARC to emit an unbalanced retain or release, respectively, is poor form.

纯粹使用__bridge_retained或__bridge_transfer强制转换来说服ARC分别发出不平衡的保留或释放,这种形式很糟糕。

Now,

void *t = (void *)self; // ERROR: Cast of ... requires a bridged cast Why it wrong because you trying to casting reference from Objective-C to C. It failed to pass ownership of reference.

void * t =(void *)self; // ERROR:Cast of ...需要一个桥接演员为什么它错了,因为你试图将引用从Objective-C转换为C.它未能通过引用的所有权。

void *t = (__bridge void *)self; // CORRECT Why it correct because to transfer your objective-C reference to C. According to doc of LLVM. See above given casting rules.

void * t =(__ bridge void *)self; //正确为什么它正确,因为将您的Objective-C引用转移到C.根据LLVM的文档。见上面给出的铸造规则。

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

Above lines are completely still ok because you pass C reference type context instead of NULL

上面的行完全没问题因为你传递了C引用类型上下文而不是NULL