170

With ARC, I can no longer cast CGColorRef to id. I learned that I need to do a bridged cast. According clang docs:

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.

In what kind of situations would I use each?

For example, CAGradientLayer has a colors property which accepts an array of CGColorRefs. My guess is that I should use __brige here, but exactly why I should (or should not) is unclear.

Todd Lehman
  • 2,880
  • 1
  • 26
  • 32
Morrowless
  • 6,856
  • 11
  • 51
  • 81
  • 17
    Have you watched WWDC 2011 session 323 yet? That explains ARC far better than I could here. It covers all the details from beginning to end. It's a must see session for every Mac/iOS developer. – rbrown Aug 12 '11 at 06:36
  • This might help too: http://stackoverflow.com/questions/14352494/bridged-cast-bridge-transfer-vs-bridge-with-synthesized-setter/28495303#28495303 – Ewan Mellor Apr 15 '15 at 09:23
  • Link to WWDC session, it wasn't trivial to find: developer.apple.com/videos/play/wwdc2011/323 – Relevant bit is at 23:15 – Daniel Jul 22 '19 at 17:12

3 Answers3

219

I agree that the description is confusing. Since I just grasped them, I'll try to summarize:

  • (__bridge_transfer <NSType>) op or alternatively CFBridgingRelease(op) is used to consume a retain-count of a CFTypeRef while transferring it over to ARC. This could also be represented by id someObj = (__bridge <NSType>) op; CFRelease(op);

  • (__bridge_retained <CFType>) op or alternatively CFBridgingRetain(op) is used to hand an NSObject over to CF-land while giving it a +1 retain count. You should handle a CFTypeRef you create this way the same as you would handle a result of CFStringCreateCopy(). This could also be represented by CFRetain((__bridge CFType)op); CFTypeRef someTypeRef = (__bridge CFType)op;

  • __bridge just casts between pointer-land and Objective-C object-land. If you have no inclination to use the conversions above, use this one.

Maybe this is helpful. Myself, I prefer the CFBridging… macros quite a bit over the plain casts.

Ben Mosher
  • 13,251
  • 7
  • 69
  • 80
monkeydom
  • 2,885
  • 1
  • 18
  • 12
  • Does the objects retain count get increased by arc by 1 when you use __bridge_transfer? Otherwise it would seem that the moment CFRelease() is called the object is gone and points to nothing. Similarly, when you use __bridge_retain, does ARC reduce the op's retain count by 1? Else it seems that the object would never be properly released. – Tony Dec 26 '11 at 03:14
  • 2
    Once in ARC land you don't think about retain counts anymore, only about strong and weak references. – monkeydom Jan 13 '12 at 11:56
  • 4
    Yea, if you are only in arc land strong / weak would be enough, however when you are transitioning objects between arc and non-arc environments you still do have to think about the retain count implications under the hood – Tony Jan 13 '12 at 17:30
  • 3
    Not really. You need to think just about getting in and out of ARC land. And this is quite remenicent of grasping autoreleasing. (interestingly enough: ARC fixes a common pattern like getting an object out of a dictionary and then removing it before using it, etc.) – monkeydom Apr 13 '12 at 16:16
  • 3
    using the Analyzer tool (shift + command + B) can help in resolving such kind of doubts, as it will tell you in a natural language if the current code is leaking memory. If it does, you are probably using a retaining cast while you should use a non-retaining cast. if the Analyzer does not warn you about anything in that code lines, you are probably doing well with the current code – Fabio Napodano Jul 01 '13 at 09:37
57

I found another explanation in the iOS documentation that I think is easier to understand:

  • __bridge transfers a pointer between Objective-C and Core Foundation with no transfer of ownership.

  • __bridge_retained (CFBridgingRetain) casts an Objective-C pointer to a Core Foundation pointer and also transfers ownership to you.

    You are responsible for calling CFRelease or a related function to relinquish ownership of the object.

  • __bridge_transfer (CFBridgingRelease) moves a non-Objective-C pointer to Objective-C and also transfers ownership to ARC.

    ARC is responsible for relinquishing ownership of the object.

Source: Toll-Free Bridged Types

hashier
  • 4,670
  • 1
  • 28
  • 41
gregschlom
  • 4,825
  • 4
  • 28
  • 23
33

As a follow-on, in this specific case, if you are on iOS, Apple recommends using UIColor and its -CGColor method to return the CGColorRef into the colors NSArray. In the Transitioning to ARC Release Notes, under the section "The Compiler Handles CF Objects Returned From Cocoa Methods", it is indicated that using a method like -CGColor which returns a Core Foundation object will automatically be handled properly by the compiler.

Thus, they suggest using code like the following:

CAGradientLayer *gradientLayer = (CAGradientLayer *)[self layer];
gradientLayer.colors = [NSArray arrayWithObjects:(id)[[UIColor darkGrayColor] CGColor],
                                                 (id)[[UIColor lightGrayColor] CGColor], nil];

Note that as of right now, Apple's example code is missing the (id) cast I have above, which is still necessary to avoid a compiler error.

Brad Larson
  • 170,088
  • 45
  • 397
  • 571
  • You can usually get away with just casting the first of the objects to (id) instead of all of them, if you prefer. – Philippe Sabourin Nov 22 '11 at 20:25
  • 1
    This question asks about casting with ARC, where the code you've pasted is not legal. – Joey Hagedorn Jan 22 '12 at 06:59
  • 11
    @JoeyHagedorn - Perhaps you missed my reference to the ARC documentation in the first sentence of my answer, but not only is this valid under ARC, it is the recommended approach for providing CGColorRef references into NSArrays from these UIColor converter methods. I, and many others, use this exact code within ARC-enabled applications. The immediate casting to (id) from a method that returns a Core Foundation object automatically bridges that object to ARC properly. – Brad Larson Jan 22 '12 at 17:36