Crash on return NULL (NSData*) from Objective-C

I have a Swift project with a Bridging-Header to the following Objective-C method:

- (NSData* _Nullable)get_data_pointer_without_error; // header

- (NSData*)get_data_pointer_without_error {
    return NULL;
}

The Swift signature (as expected) is func get_data_pointer_without_error() -> Data?. When I call this from Swift it successfully returns a nil Data?. But here is the same method which also can throw an error:

- (NSData* _Nullable)get_data_pointer_with_error:(NSError* _Nullable* _Nullable)error; // header

- (NSData*)get_data_pointer_with_error:(NSError* _Nullable* _Nullable)error {
    return NULL;
}

When I call this from Swift it crashes with the error shown below. Xcode shows that the Swift signature is func get_data_pointer_with_error() throws -> Data. It adds throws as expected, but instead of Data? it returns Data. (No surprise that the return of NULL from Objective-C makes it crash.)

My question: How to return a nullable NSData* from an Objective-C method which also throws?

Sample project: https://github.com/jefft0/swift-objc-data/blob/main/swift-objc-data/main.swift

Output:

get_data_pointer_without_error returned
Fatal error: Error raised at top level: Foundation._GenericObjCError.nilError: file /AppleInternal/BuildRoot/Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-1103.8.25.8/swift/stdlib/public/core/ErrorType.swift, line 200

My question: How to return a nullable [pointer] from an Objective-C method which also throws?

There’s a function attribute for that: swift_error. It’s hinted at in the documentation here and described fully at https://clang.llvm.org/docs/AttributeReference.html#swift-error.

The default behavior, as you have seen, is equivalent to __attribute__((swift_error(null_result))).

In your case, you’ll want to use __attribute__((swift_error(nonnull_error))). Then throwing will be controlled by whether you populate the error out-parameter.

Thanks for the quick and useful answer!

Then throwing will be controlled by whether you populate the error out-parameter.

Having said that, I recommend that you not do this because it’s not the standard convention. Anyone using your code from Objective-C will expect it to follow standard Cocoa error handling conventions, and that means:

  • A function result of nil indicates an error.

  • The NSError out parameter is optional.

  • The NSError out parameter is populated if it’s present and an error is indicated by the function result.

For more on this, see the Error Handling Programming Guide.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Crash on return NULL (NSData*) from Objective-C
 
 
Q