Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 469
zumzum Avatar asked Jun 21 '13 03:06

zumzum


1 Answers

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 or 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 or 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.

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;
like image 173
Gabriele Petronella Avatar answered Oct 20 '22 12:10

Gabriele Petronella