Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Releasing CFStringRef after casting to NSString

I'm converting an Objective-C function which casts a CFStringRef to an NSString like so (where FSEventStreamCopyDescription returns a CFStringRef):

return (NSString *)FSEventStreamCopyDescription(eventStream);

However, upon analyzing my application I'm told that this will cause a 'potential leak', due to the absence of a CFRelease call. I'm attempting to rewrite this function to avoid any leaks. What's the correct way of handling this? I've provided two possibilities (both of which could be incorrect):

Option A:

CFStringRef ref = FSEventStreamCopyDescription(eventStream);
NSString *desc = [(NSString *)ref copy];
CFRelease(ref);

return [desc autorelease];

Option B:

CFStringRef ref = FSEventStreamCopyDescription(eventStream);
NSString *desc = [[NSString alloc] initWithString:(NSString *)ref];
CFRelease(ref);

return [desc autorelease];
like image 685
ndg Avatar asked May 10 '11 14:05

ndg


3 Answers

Casting does not do anything to the object. A cast only tells the compiler “this is really a _____”.

It also doesn't do anything to the memory management rules. You still have an object that you obtained from a function that follows the CF rules and contains Copy in its name. Therefore, you own that object; therefore, you are responsible for releasing it.

It is not the name of the class that matters; toll-free bridging means that a CFString is an NSString. What matters is what rules the function or method you got the object from follows (CF rules or Foundation rules), and whether you obey them.

Both Options A and B solve the problem, but with excess complexity.

The copy and release in Option A achieves nothing. You already copied it; making another copy does not change the situation. It only wastes time, both yours and the user's.

The initWithString: (or stringWithString:) of Option B also achieves nothing. You already have a CFString, and a CFString is an NSString, so you don't need to create an NSString. Ultimately, this is equivalent to Option A.

@kubi's answer is the best so far, but bears one improvement:

return [NSMakeCollectable(FSEventStreamCopyDescription(eventStream)) autorelease];

With this change, the code will work correctly under garbage collection, where autorelease does nothing. Meanwhile, under retain/release rules, NSMakeCollectable does nothing. Either way, your ownership will be released/collected at the appropriate time.

like image 118
Peter Hosey Avatar answered Nov 05 '22 22:11

Peter Hosey


Either will work. My preference is option A.

You can also use NSString's -stringWithString: method which returns you a string that doesn't need auto releasing.

CFStringRef ref = FSEventStreamCopyDescription(eventStream);
NSString *desc = [NSString stringWithString: (NSString *)ref];
CFRelease(ref);

return desc;
like image 2
JeremyP Avatar answered Nov 05 '22 22:11

JeremyP


Third option:

return [(NSString *)FSEventStreamCopyDescription(eventStream) autorelease];
like image 2
kubi Avatar answered Nov 05 '22 22:11

kubi