Question

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

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

So are C function calls:

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:

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:

[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?

Was it helpful?

Solution

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

3.3.3 Conversion from retainable object pointer type in certain contexts

[beginning 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:

  • to initialize a parameter in an Objective-C message send where the parameter is not marked with the cf_consumed attribute, or to
  • initialize a parameter in a direct call to an audited function where the parameter is not marked with the cf_consumed attribute.

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*).

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.

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.

OTHER TIPS

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

Go through Clang's doc:

Bridged casts

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

(__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.

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.

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

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 = (__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.

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

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top