NSString to CFStringRef and CFStringRef to NSString in ARC?
Asked Answered
F

1

97

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?

Female answered 21/6, 2013 at 3:41 Comment(7)
CFStringRef foo (__bridge CFStringRef)theNSString; and NSString *bar = (__bridge NSString *)theCFString;Pussyfoot
Could you explain what is really happening in details when those two options are used?Female
Not quite. I don't use ARC, so all I know is that you have to do this, but not the why.Pussyfoot
@H2CO3 out of curiosity, any particular reason why you don't use ARC?Karole
@GabrielePetronella ARC was supposed to make coding easy, code shorter and more readable and reduce the possibility for human errors. So, now instead of having to take care of reference counts by retaining and release-ing objects, we must now use "beautiful" casts like __bridge_transfer, __unsafe_unretained and __autoreleasing. Nobody ain't got no time for that. (And seriously, it's harder to read. In my opinion, it didn't facilitate memory management at all.)Pussyfoot
@H2CO3 thank you for the answer. I strongly disagree, especially with the last sentence, but I respect your point of view :)Karole
@GabrielePetronella is missing the point of ARC; to auto-reference count ObjC objects; and for that it's just fine (no casting required). The casts are only necessary to bridge the gap between the ObjC object and Core Foundation.Caneghem
K
193

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;
Karole answered 23/6, 2013 at 1:34 Comment(3)
Thanks you very much, this is not really intuitive, but thanks to you, lesson learnedFlam
@: little question. so if we use ARC. when NSString->CFString, we should use __bridge. but when CFString->NSString, we should use __bride_transfer. ? And any side-effect, if we use CFRelease when we don't need too. thanks :)Phosphocreatine
@hqt, if you want the 'easy' way, yes what you say is correct. Also, an extra CFRelease should reasonably crash your program, since you will end up with mismatched retain/release operation, eventually releasing a NULL pointer.Karole

© 2022 - 2024 — McMap. All rights reserved.