Reputation: 2070
Let's say a method returns a CFErrorRef
via a pointer. This returned error may be NULL
. So would it be safe to perform a __bridge_transfer
still or should I check for NULL
.
E.g.
CFErrorRef cfError;
ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, &cfError);
NSError *error = (__bridge_transfer NSError *)cfError;
I don't see any mention of this in the documentation and CFRelease
documentation specifically states This value must not be NULL.
https://developer.apple.com/library/mac/documentation/CoreFoundation/Reference/CFTypeRef/Reference/reference.html#//apple_ref/c/func/CFRelease
Upvotes: 4
Views: 1004
Reputation: 44886
The direct answer to the question is yes, you can use __bridge_transfer
on NULL
. But this isn't the right question.
Read the documentation on ABAddressBookCreateWithOptions
. In particular, check out the documentation for error
:
On error, contains error information. See “Address Book Errors.”
This is important.
error
's value in the case of success is not documented.error
being nil
/NULL
/0
(ever) is not documented.This isn't academic. Some APIs have historically set error to invalid values. Imagine the call set the CFError
to -1
. That's "valid" since the non-NULL
reply means you're not supposed to interpret the error, but bridge casting -1
to a NSError
will probably crash.
That means you must not touch cfError
unless an error is indicated by ABAddressBookCreateWithOptions
returning NULL.
CFErrorRef cfError;
NSError *error;
ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, &cfError);
if (addressBookRef == NULL) {
error = (__bridge_transfer NSError *)cfError;
}
You didn't ask this, but one additional wrinkle here is that bridges aren't even required if the compiler recognizes that something is 0-equivalent. For instance, this code will compile silently (assuming _thing1
and _thing2
are instance variables):
- (id)bar {
if (_thing1) return NO;
if (_thing2) return 0;
return NULL;
}
This is sloppy code, and I you should not do this intentionally, but knowing it builds cleanly… it's a good thing to look for. I ran into a bug caused by something like this:
- (NSNumber *)someCalculationWithError:(NSError *)error {
return 0; // meant to return @(0)
}
Upvotes: 2
Reputation: 12782
The error will be non NULL if the return value of the function is NULL.
The pattern for this kind of CF function is to wrap the error checking in an if statement.
if (addressBookRef == NULL) { /* your error handling here */}
You should not try to bridge anything unless it is non NULL. Object ownership or more accurately retain count and responsibility for decrementing it, are not meaningful with NULL or nil. It would be an anti pattern. At best it's a null operation. Sending messages to nil with Objective-C is fine, including retain and release. It is not fine to pass a NULL value to CFRelease() or CGRetain()
Upvotes: 2
Reputation: 25619
You do not need to check for NULL.
ARC is a strictly compile-time mechanism. When you use __bridge_transfer
you are merely transferring memory management responsibility of a variable to the compiler. Whether cfError
happens to be NULL or not at runtime is completely irrelevant to the compiler.
In your case, ARC will insert a release for error
, but if error
happens to be nil it's a simple no-op.
Upvotes: 3
Reputation: 131481
Unlike NSObjects, sending messages to NULL CF objects is not ok. I don't know about bridging casts specifically, but I would guess that no, casting a CF object to an NSObject using __bridge_transfer is NOT ok.
Why not try it and see? Cast it to a variable in the local scope of an instance method. That way, as soon as the method goes out of scope the system should try to release the object.
Upvotes: 0