3
votes

I'm getting an "ambiguous use of init" error when building with Xcode 7.3 and Swift 2.2

The issue is related to two Objective-C classes and how Swift views their initializers.

Objc sees:

Superclass

@interface Foo: NSManagedObject
+(instancetype)fooWithOwner:(Owner *)owner insertIntoManagedObjectContext:(NSManagedObjectContext *)context;

Subclass

@interface Bar: Foo
+(instancetype)barWithOwner:(Owner *)owner insertIntoManagedObjectContext:(NSManagedObjectContext *)context;

while Swift only sees:

init(owner: Owner!, insertIntoManagedObjectContext context: NSManagedObjectContext!)

which is causing the compiler to be unsure of which init is being called on the subclass "Bar". Is there a way to specify which initializer to use when initializing the subclass? I'd like to avoid refactoring the init method if possible.

2
You can rename to makeFooWithOwner... and makeBarWithOwner... or something similar and it won't convert them to initializersdan
Can you post the Swift code that you're having the problem with? I copy/pasted into a new project and didn't have any trouble compiling.Kevin
there is no reason why the original Obj-C methods should have different names in the first place.Sulthan

2 Answers

4
votes

It is due to ObjC->Swift API translation rules.

You can use swift_name attribute to overwrite these rules.

@interface Foo: NSManagedObject
+(instancetype)fooWithOwner:(Owner *)owner insertIntoManagedObjectContext:(NSManagedObjectContext *)context NS_SWIFT_NAME(foo(owner:moc:));

@interface Bar: Foo
+(instancetype)barWithOwner:(Owner *)owner insertIntoManagedObjectContext:(NSManagedObjectContext *)context NS_SWIFT_NAME(bar(owner:moc:));

Then you can call them separately in Swift code:

let foo = Bar.foo(owner: owner, moc: context)
let bar = Bar.bar(owner: owner, moc: context)
0
votes

I'm not sure what's going on, btw I tried this. In the ObjC header I added those two class methods:

+ (id)barWithInitializer:(NSString *)className
 initializer:(SEL)initializer
    argument:(id)argument;

+ (id)fooWithInitializer:(NSString *)className
                initializer:(SEL)initializer
                   argument:(id)argument;

Then in the Swift function

I have tried both with no issue / interface mismatch

return OBJCObjectFactory.barWithInitializer(className, initializer: initializer, argument: argument) as! TBase?

return OBJCObjectFactory.fooWithInitializer(className, initializer: initializer, argument: argument) as! TBase?