On Dec 7 '13 at 16:05, Tom added:
Update: Thanks to Greg, correct code is now:
CFErrorRef cfError = nil;
BOOL blessed = SMJobBless(kSMDomainSystemLaunchd,
(__bridge CFStringRef) daemonBundleID,
auth,
&cfError);
if (!blessed) {
NSError *error = (__bridge NSError *)cfError;
NSLog(@"Failed to bless PacketTool: %@", error);
[NSApp presentError: error];
return FALSE;
}
I know that this post is 2 years old but it is wrong and I don't want other programmers copying that wrong code. This code leaks memory as the CFError is never released!
CoreFoundation has no automatic memory management, also not when using ARC. ARC only applies to Obj-C objects. And CoreFoundation doesn't know autorelease or autorelease pools, so CoreFoundation objects (CFStringRef
, CFNumberRef
, CFErrorRef
, etc.) you get from CoreFoundation functions are never autoreleasing. They either don't need to be released at all or it's up to you to release them. And in case of out errors (CFErrorRef *
), it's up to you to release them.
See also https://stackoverflow.com/a/8628267/15809
The first part of the code is correct:
CFErrorRef cfError = nil;
BOOL blessed = SMJobBless(
kSMDomainSystemLaunchd,
(__bridge CFStringRef)daemonBundleID,
auth, &cfError
);
But then you need to understand bridge casting. The simplest form or bridge casting is just __bridge
and this cast tells ARC "don't do anything". If you do this
NSError * error = (__bridge NSError *)cfError;
You tell ARC: "Cast cfError
to error
but don't manage the memory of error after the cast, it's none of your business."
If you do this, you are still responsible for releasing the CFErrorRef
! That means once you are done with cfError
and with error
("and" as both point to the same object and if that is destroyed both pointers become invalid), you must do this:
CFRelease(cfError);
Otherwise you are leaking memory!
Alternatively you can tell ARC to manage the memory for you but then you need a different cast. If you cast like that
NSError * error = (__bridge_transfer NSError *)cfError;
you tell ARC: "Cast cfError
to error
and then its up to you to manage the memory of error
."
Now you don't need to release anything since as soon as error
goes out of scope, ARC will release it for you. And because error
and cfError
are in fact the same object, releasing error
also releases cfError
, so now you don't need to release anything. As the name implies, this cast "transfers" the object to ARC. Once that is done, you must not use cfError
at all any longer as you cannot say for sure when exactly ARC will release error
and as soon as it does, cfError
is an invalid pointer, using it can easily crash your whole app.
Same holds true if you cast into the other direction. If you do
NSError * error = ...;
CFErrorRef cfError = (__bridge CFErrorRef)error;
ARC will still manage the memory of error
, which is dangerous as, see above, when ARC decides it can destroy error
, cfError
will also become invalid. It is okay if you only use cfError
in the current scope, but if your CFErrorRef
needs survive regardless what ARC does, then you do this cast:
NSError * error = ...;
CFErrorRef cfError = (__bridge_retained CFErrorRef)error;
This tells ARC: "Retain error
once, then cast error
to cfError
and don't ever balance this initial retain."
So even when error
goes out of scope, it won't be released by ARC as the retain counter of the object won't become 0, it will still at least be 1 because of that cast. It's now up to you to take care of memory management and that means once you are done with cfError
, you must release it:
CFRelease(cfError);