NSString to CFStringRef and CFStringRef to NSString in ARC?
I am trying to understand the correct way of getting an NSString
from a CFStringRef
in ARC?
Same for going the opposite direction, CFStringRef
to NSString
in ARC?
What is the correct way to do this without creating memory leaks?
Typically
NSString *yourFriendlyNSString = (__bridge NSString *)yourFriendlyCFString;
and
CFStringRef yourFriendlyCFString = (__bridge CFStringRef)yourFriendlyNSString;
Now, if you want to know why the __bridge
keyword is there, you can refer to the Apple documentation. There you will find:
__bridge
transfers a pointer between Objective-C and Core Foundation with no transfer of ownership.
__bridge_retained
orCFBridgingRetain
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
orCFBridgingRelease
moves a non-Objective-C pointer to Objective-C and also transfers ownership to ARC. ARC is responsible for relinquishing ownership of the object.
Which means that in the above cases you are casting the object without changing the ownership. This implies that in neither case you will be in charge of handling the memory of the strings.
There may also be the case in which you want to transfer the ownership for some reason.
For instance consider the following snippet
- (void)sayHi {
CFStringRef str = CFStringCreateWithCString(NULL, "Hello World!", kCFStringEncodingMacRoman);
NSString * aNSString = (__bridge NSString *)str;
NSLog(@"%@", aNSString);
CFRelease(str); //you have to release the string because you created it with a 'Create' CF function
}
in such a case you may want to save a CFRelease
by transferring the ownership when casting.
- (void)sayHi {
CFStringRef str = CFStringCreateWithCString(NULL, "Hello World!", kCFStringEncodingMacRoman);
NSString * aNSString = (__bridge_transfer NSString *)str;
// or alternatively
NSString * aNSString = (NSString *)CFBridgingRelease(str);
NSLog(@"%@", aNSString);
}
The ownership of str
has been transferred, so now ARC will kick in and release the memory for you.
On the other way around you can cast a NSString *
to a CFString
using a __bridge_retained
cast, so that you will own the object and you'll have to explicitly release it by using CFRelease
.
To wrap it up you can have
NSString → CFString
// Don't transfer ownership. You won't have to call `CFRelease`
CFStringRef str = (__bridge CFStringRef)string;
// Transfer ownership (i.e. get ARC out of the way). The object is now yours and you must call `CFRelease` when you're done with it
CFStringRef str = (__bridge_retained CFStringRef)string // you will have to call `CFRelease`
CFString → NSString
// Don't transfer ownership. ARC stays out of the way, and you must call `CFRelease` on `str` if appropriate (depending on how the `CFString` was created)
NSString *string = (__bridge NSString *)str;
// Transfer ownership to ARC. ARC kicks in and it's now in charge of releasing the string object. You won't have to explicitly call `CFRelease` on `str`
NSString *string = (__bridge_transfer NSString *)str;