问题
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) opcasts the operand to the destination typeT. IfTis a retainable object pointer type, thenopmust have a non-retainable pointer type. IfTis 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) opcasts 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) opcasts 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_retainedor__bridge_transfercast 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.
回答1:
I agree that the description is confusing. Since I just grasped them, I'll try to summarize:
(__bridge_transfer <NSType>) opor alternativelyCFBridgingRelease(op)is used to consume a retain-count of aCFTypeRefwhile transferring it over to ARC. This could also be represented byid someObj = (__bridge <NSType>) op; CFRelease(op);(__bridge_retained <CFType>) opor alternativelyCFBridgingRetain(op)is used to hand anNSObjectover to CF-land while giving it a +1 retain count. You should handle aCFTypeRefyou create this way the same as you would handle a result ofCFStringCreateCopy(). This could also be represented byCFRetain((__bridge CFType)op); CFTypeRef someTypeRef = (__bridge CFType)op;__bridgejust 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.
回答2:
I found another explanation in the iOS documentation that I think is easier to understand:
__bridgetransfers 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
回答3:
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.
来源:https://stackoverflow.com/questions/7036350/arc-and-bridged-cast