Reputation: 2618
I have a framework target in which most of the classes are written in Objective C. Recently we have started introducing Swift files in the code. We make private Objective C files available to swift code using modules(more on this can be found here).
This approach worked well until recently when I tried subclassing one of my Objective C class using Swift, I got an error in the Generated MyFramework-Swift.h
file which said "Module TestSwift
not found" where TestSwift
is the name of the module I provided in the modulemap
file. However, if I try subclassing the classes which are listed in the umbrella header of my framework(public classes), it works.
import TestSwift
@objc public class NewSwiftClass: ExistingObjectiveCClass {
//throws error in the generated MyFramework-Swift.h file while compiling
}
If I keep my swift class internal, it works
import TestSwift
@objc class NewSwiftClass: ExistingObjectiveCClass {
//works fine
}
but I would like to use this Swift class in my Objective C files hence cannot keep it internal.
TL;DR: I'm unable to subclass an existing Objective C class using Swift inside a framework target.
Upvotes: 1
Views: 983
Reputation: 22325
I believe this is impossible in Swift because it's impossible in Objective-C.
If you have a class A
in your framework that is not part of your umbrella header, and you want B
to subclass it and be in your umbrella header, you can't do it.
You have to declare the inheritance in your interface declaration @interface B: A
, which goes in B's header and thus in the umbrella header. But the compiler is going to complain: "What is A?" You could import A's header there, but unlike Swift's import
, Objective-C's #import
literally drops the contents of A's header into the B header. Which means A is now in the umbrella header too i.e. public.
Mixing Swift with Objective-C isn't magic. The compiler still needs to be able to make a valid Objective-C header that accurately describes the Swift interface. So unless you can think of a way to make Objective-C do this, you can't do it in Swift.
The only alternative I can think of is to change your "is a" relationship into a "has a" relationship i.e.
@objc public class NewSwiftClass {
let parent: ExistingObjectiveCClass
}
obviously you lose most of the benefits of actual inheritance but you'll still have the parent around as a substitute for super
. You could also declare a public protocol that both classes conform to to ensure that you get consistency between their methods.
Upvotes: 1