You want to know how to use new typecasting facilities under Automatic Reference Counting in order to avoid memory leaks when working with Core Foundation objects inside your Objective-C code.
Typecasting is the process of pointing one value of type A to
another value of type B. For instance, if you have a Core Foundation
string object of type CFStringRef
and you would like to place it inside an Objective-C string of type
NSString
, you can easily create an
error:
- (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ CFStringRef coreFoundationString = CFStringCreateWithCString(CFAllocatorGetDefault(), "C String", kCFStringEncodingUTF8); /* Compile time error!!! */ NSString *objCString = coreFoundationString; self.window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]]; self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible]; return YES; }
Here we are assigning the value of the Core Foundation string
coreFoundationString
to the
Objective-C string of type NSString
named objCString
, our compiler will
get confused because it doesn’t know what we are intending to do with
the memory assigned to each one of these objects. Additionally, we
will end up with a memory leak because the compiler doesn’t know how
to get rid of the Core Foundation object for us automatically.
Remember that Automatic Reference Counting does
not work for Core Foundation objects, so we need
to assist the compiler. To do this, let’s try to understand what each
one of these typecasting specifiers does:
__bridge
Simply typecasts the object on the right side of the equation to the left side. This will not modify the retain count on any of the objects; neither the one on the left nor the one on the right side of the equation.
__bridge_transfer
This typecast will assign the object on the right side to the object on the left and will release the object on the right side. So if you have a Core Foundation string, like the one we saw before, that you have just created and want to place it inside a local variable of type
NSString
(local variables are by default strong, see Recipe 1.17), then you should use this typecasting option because then you wouldn’t have to release the Core Foundation string after the assignment. We will see an example of this soon.__bridge_retained
This is similar to the
__bridge_transfer
typecast, but will retain the object on the right side of the equation as well.
Let’s try to fix the example code we saw before. Our goal is to
place the Core Foundation string into an instance of NSString
(strong, by default) and then
automatically release the Core Foundation string. To do this, we must
use the __bridge_transfer
typecasting option:
- (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ CFStringRef coreFoundationString = CFStringCreateWithCString(CFAllocatorGetDefault(), "C String", kCFStringEncodingUTF8); /* Compile time error!!! */ NSString *objCString = (__bridge_transfer NSString *)coreFoundationString; NSLog(@"String = %@", objCString); self.window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]]; self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible]; return YES; }
What happened here was that we created a new Core Foundation
object. The retain count on this object is 1 at this time. Then we
typecasted and assigned it, using the __bridge_transfer
typecast option, to a
strong local variable of type NSString
. But this time, because the
compiler sees the typecasting, it will retain the Core Foundation
string and place it inside the local variable (since the local
variable is strong
by default) and
after the assignment, will release the Core Foundation string.
Perfect! Exactly what we wanted.
Now let’s have a look at when we would use __bridge_retained
. This typecasting option
is used whenever we would like the object on the right side of the
equation to still exist after the assignment. Here is an
example:
- (BOOL) application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{ CFStringRef coreFoundationString = CFStringCreateWithCString(CFAllocatorGetDefault(), "C String", kCFStringEncodingUTF8); id unknownObjectType = (__bridge id)coreFoundationString; CFStringRef anotherString = (__bridge_retained CFStringRef)unknownObjectType; NSString *objCString = (__bridge_transfer NSString *)coreFoundationString; NSLog(@"String = %@", objCString); objCString = nil; CFRelease(anotherString); self.window = [[UIWindow alloc] initWithFrame: [[UIScreen mainScreen] bounds]]; self.window.backgroundColor = [UIColor whiteColor]; [self.window makeKeyAndVisible]; return YES; }
Here is what is happening in this code:
We allocated a Core Foundation string and placed it inside the
coreFoundationString
local variable. Since this is a Core Foundation object, ARC will not apply storage attributes to it, so we need to handle its memory manually. Its retain count is 1, as with any newly created variable.Then we typecast this Core Foundation string to a generic object of type
id
. Note that we didn’t retain or release this object, so the retain count on bothunknown
ObjectType
andcoreFoundationString
stays 1. We simply typecasted it to an object of typeid
.Now we are retaining the generic object of type
id
and placing the resulting object into another Core Foundation string. At this time, the retain count on thecoreFoundationString
,unknownObjectType
, andanotherString
variables is 2 and all three of these variables point to the same location in the memory.What we are doing after that is to assign the value inside
coreFoundationString
to a strong localNSString
using the__bridge_transfer
typecasting option. This will make sure that thecoreFoundationString
object will get released after this assignment (the retain count will go from 2 to 1) and it will again be retained (because of the strongNSString
variable, shooting the retain count from 1 to 2 again) So nowcoreFoundationString
,unknownObjectType
,anotherString
and theobjCString
variables all point to the same string with the retain count of 2.The next stop is setting our strong local variable
objCString
tonil
. This will release this variable and our string’s retain count will go back to 1. All these local variables are still valid and you can read from them because the retain count of the string that all of them point to is still 1.Then we are explicitly releasing the value in the
anotherString
variable. This will set the release count of our object from 1 to 0 and our string object will get deallocated. At this point, you should not use any of these local variables because they are pointing to a deallocated object—except for theobjCString
strong local variable, whose value was set tonil
by us.
Get iOS 5 Programming Cookbook now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.