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];
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.
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;
Third option:
return [(NSString *)FSEventStreamCopyDescription(eventStream) autorelease];
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With