Paying the ARC __bridge toll

After years spent writing Objective-C code and getting completely comfortable with balancing every alloc, retain and copy with a release or autorelease, ARC messed with my brain a bit when I first encountered it. At first I ignored it, because it’s optional, but when I discovered that in general it produces faster code, I started reading up on, and then using ARC.

After a while I’ve gotten comfortable with no longer thinking about object ownership in Objective-C when ARC is enabled. Except of course for occasions where I need to use (weak) in property declarations, mostly for delegates.

But one thing that hadn’t crossed my path until recently was toll free bridging from Core Foundation to Objective-C, and at first it was also quite confusing. Especially since ARC means that you really don’t think about this anymore for Objective-C, having to think again for CF is a bit of a jolt.

The Transitioning to ARC Release Notes provide this example of equivalent code, first non ARC, then ARC:

- (void)logFirstNameOfPerson:(ABRecordRef)person
{
    NSString *name = (NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);
    NSLog(@"Person's first name: %@", name);
    [name release];
}

- (void)logFirstNameOfPerson:(ABRecordRef)person
{
    NSString *name = (NSString *)CFBridgingRelease(ABRecordCopyValue(person, kABPersonFirstNameProperty));
    NSLog(@"Person's first name: %@", name);
}

This is helpful to see one example of how to start using ARC, but when migrating code the compiler actually prompts you to fill in with __bridge style cast specifiers, and that seems to be the style that’s used a lot. So I had to understand how these differed, and I’ve come up with two more equivalent bits of ARC code that helped me understand:

- (void)logFirstNameOfPerson:(ABRecordRef)person
{
    NSString *name = (__bridge_transfer NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);
    NSLog(@"Person's first name: %@", name);
}

- (void)logFirstNameOfPerson:(ABRecordRef)person
{
    CFStringRef nameRef = ABRecordCopyValue(person, kABPersonFirstNameProperty);
    NSString *name = (__bridge NSString *)nameRef;
    NSLog(@"Person's first name: %@", name);
    CFRelease(nameRef); // balance the *Copy*()
}

There are some things to consider:

So, in cases like this one, you actually have to choose between explicitly balancing the *Copy*() call with a *Release(), or handing over to ARC, using one of two styles. Which of these is preferable? I have no idea. I guess some kind of community consensus will develop over time, if it hasn’t already, and we’ll all just do it that way.