My recent posts were about SwiftUI quirks and annoyances, so I want to share a short success story for a change:
@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!
Fortunately, CorePlot itself is written in Objective-C. The Package manifest doesn’t even look funny:
.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!