I have a package that's written in Swift only, and now I'd love to make it work for objective-c projects. I know usually to use Swift classes in the same target you can use the bridging header created for the module, but when I import my package through SPM, there is no prompt to create a bridging header. Is this possible? Do I have to prep my swift package in certain ways first?
1 Answer
There is surprisingly little amount of documentation about this online, but I finally figured it out. It's not as easy as making some change in your package.Swift file and click some buttons, but luckily it's not too difficult either. I'm still working on fully making my Swift library to be usable in Objc, and will update this answer with any findings I find along the way, but here is what I have so far:
- A class in Swift can only be used in objc if it inherits from NSObject
public final class MyObjcLibrary: NSObject {}
- To export it to objc, you need to append the
@objckeyword, and you can specify the class name used by objc code with a parentheses following the keyword - this is very handy when your objc class is just a wrapper with a bunch of exported functions of your corresponding Swift class:
@objc(MyLibrary)
public final class MyObjcLibrary: NSObject{}
This way, the user of your library can write [MyLibrary alloc] instead of [MyObjcLibrary alloc].
- Now you can add all the functions (with the
@objckeyword) your users need to use in your new class. Assuming you have a Swift class namedMyLibrary:
@objc(MyLibrary)
public final class MyObjcLibrary: NSObject{
private var myLibrary: MyLibrary
@objc public init() {
myLibrary = MyLibrary()
}
@objc public static func doSomething(withID: String) {
myLibrary.doSomething(withID)
}
@objc public static func doSomethingElse(ID: String) {
myLibrary.doSomethingElse(ID)
}
...
}
- To import and call your classes and functions in your objc code, you just add the package the same way you add a Swift package, through SPM, Cocoapods, etc, then in your objc class:
@import MyPackage
...
[[MyLibrary alloc] init];
[MyLibrary doSomethingWithID:@"my_id"];
[MyLibrary doSomethingElseWithID:@"my_id"];
...
Notice how the functions are named in objc - if the first parameter does not start with the prefix "with", it's automatically added for the objc function signature, e.g. doSomethingElseWithID.
Problems I've seen:
- when your Swift library has updates, sometimes you need to restart Xcode and remove your DerivedData folder for the bridging header files to be regenerated with updated code.
5 Comments
@objcMembers which can save a lot of typing.@objcMembers btw, looking into it now! I have done a lot of googling on this topic and I have not seen it.