Swift Package Import in Objective-C Might Just Work
My recent posts were about SwiftUI quirks and annoyances, so I want to share a short success story for a change:
You can @import
Swift Packages in Objective-C code just fine. (At least if they are Objective-C compatible.)
How I Got Here
I updated my WordCounter app to rely less on Carthage and use Swift packages where possible instead.
The WordCounter’s dependencies are simple in comparison to my other apps, so I merely had to update a handful of sub-projects to expose a Swift Package manifest, bump some deployment targets, and that was it.
When I began deleting the pertinent lines from the Cartfile
and began to add the package paths to Xcode, I realized that the WordCounter’s graphs are still drawn from Objective-C NSView
subclasses that use CorePlot. I also use CorePlot in one of my internal modules. Wouldn’t this cause all kinds of trouble?
In hindsight, I feel stupid for even trying the following, but in the spirit of sharing, enjoy what won’t work:
I kept the CorePlot entry in the Cartfile
. This compiled the CorePlot.xcframework
, and I linked and embdeded this framework in the app so Objective-C would be able to #import <CorePlot/CorePlot.h>
. I also kept the Swift Package managed CorePlot dependency from my internal module I just updated. The linker wasn’t happy about the confusion, of course, and the app wouldn’t run. After sitting on this for a day or three, I recalled that I could import the Swift Package managed CorePlot module in a .framework
target and use this as an “umbrella” framework! So I researched how to best approach this. Instead, I found that people complained about Objective-C files in Xcode 11 not importing Swift Package modules correctly. Which implies it should.
So today, I replaced #import <CorePlot/CorePlot.h>
with @import CorePlot;
in a handful of Objective-C files and that’s it. No fancy workarounds needed. Sweet!
Objective-C Compatibility
Fortunately, CorePlot itself is written in Objective-C. The Package manifest doesn’t even look funny: .h
and .m
files just work as expected. (Well, I didn’t expect that, but may you do.)
From what I gathered, Xcode will generate Objective-C header files from Swift Packages, if possible, to make @import
statements work. The imported Swift module needs to expose @objc
types for this to work, though, and this means you can’t use enums with associated values etc. But in principle, importing a Swift Package in your app’s Objective-C files should work.
That’s great news, and it saved me a lot of headaches!