Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to bridge Objective-C initWithError: method into Swift

I have a class defined in Objective-C, whose initializer is -initWithError: (the initializer can fail due to a dependence on an outside resource). I want this to bridge into Swift as init() throws. The regular initializer inherited from NSObject, -init, can be marked unavailable, as I don't want it to be used.

In Objective-C, I have:

@interface Foo : NSObject

- (instancetype _Nullable)initWithError:(NSError **)error;

@end

This works fine in Objective-C, of course.

In Swift, -initWithError gets bridged as init(error: ()) throws. This is presumably because removing withError: from the method name results in init() which conflicts with the inherited plain -init initializer. This can be called from Swift like so:

let foo = try Foo(error: ())

This is strange looking, as the error parameter is void. It would certainly be better if this were imported as init() throws. The obvious solution is to mark -init using NS_UNAVAILABLE in the Objective-C header. Unfortunately, this doesn't work. -initWithError: still gets bridged as init(error: ()), and trying to call try Foo() results in a compiler error saying that init() is unavailable in Swift.

Is there a more elegant solution to this so that try init() just works?

like image 453
Andrew Madsen Avatar asked Mar 26 '18 01:03

Andrew Madsen


1 Answers

You can rename the function using NS_SWIFT_NAME. In this case:

- (instancetype _Nullable)initWithError:(NSError **)error NS_SWIFT_NAME(init());

That said, this feels like a compiler bug. I'd suggest opening a defect.

like image 184
Rob Napier Avatar answered Oct 04 '22 22:10

Rob Napier