You want to know how to use the 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 won’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 6 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.