I would like to share our recent experiences with integrating a Swift library into an existing Objective-C project. Hopefully sharing the trials and tribulations we experienced will help you in your project. Recently we discovered a couple of nice Chart/Graph libraries for use in our projects: MPAndroidChart and ios-charts that share the same basic API across Android and iOS. ios-charts is written in Swift (v1.2 requiring Xcode 6.3) and this was our first time integrating Swift code into one of our projects.
Cuckoo for CocoaPods
We have been using CocoaPods for dependency management in our projects for quite a while and it is a great tool. It’s even the semi-official library manager for Google’s APIs & SDKs. Beginning with version 0.36, CocoaPods added support for dynamic frameworks and Swift. So, of course, our first instinct was to use CocoaPods for adding the Swift library. It seemed simple enough:
use_frameworks!to your Podfile
- It doesn’t build… :(
But it turns out that switching to using frameworks is an all or nothing proposition. Immediately the project would no longer build, with header file
#import statements complaining
file not found with <angled> include and “Symbol Not Found” when command-clicking one in Xcode. Switching to
#import "LibraryName.h" fixed it… sometimes. We tried adding the paths to the Pods folders in the project’s “Build Settings” -> “Linking” but a couple of the libraries just would not work, including GoogleAnalytics.
Apparently many CocoaPods libraries are not ready for frameworks – developers have yet to update their projects to build the new frameworks. Hopefully this will be remedied soon because the above steps are a lot simpler that what we ended up having to actually do to get it to work.
Embed a Swift sub-Project
We wanted to avoid just dragging and dropping the .swift code files into our project, thereby making it difficult to stay in sync with any upstream changes in the GitHub repository. The preferred method is to “embed” the project that builds the framework (NOT the demo project if there is one) into your main project. Here’s the steps:
- Copy the folder containing the framework code into your own project folder
- Even better, if the Swift project you want to embed is hosted on a git repository (like GitHub) set it up as a git submodule.
- Drag the
LibraryName.xcodeprojfile inside your project. If you’re using a Xcode workspace (such as a project using CocoaPods) make sure the framework is nested inside and not at the same level as the main project and Pods project
- In your project’s Target, go to “General” section and find “Embedded Binaries” (the section also says “Add embedded binaries here”.) Make sure you don’t accidentally try to add to the “Linked Frameworks and Libraries”. Click the + button and look under the new Swift framework project for
LibraryName.framework. Select it and click “Add”.
- Under “Build Settings” section for your Target, find “Build Options” and set “Embedded Content Contains Swift Code” to YES.
- Build the project (make sure you have a Debug scheme/configuration selected) but be prepared for significantly longer build times (compiling Swift is slower than Objective-C)
@import LibraryName;where LibraryName is the name of the .framework file and you’re ready to go!
Embedded Swift frameworks require Code Signing
Yep. You read it correctly. If you want to make an AdHoc or Enterprise build you will need a working iPhone Distribution certificate to do it. Debug builds should install on a registered device assuming your Team is setup and you’ve got a valid iPhone Developer certificate. When building & installing a Swift app, Xcode copies the Swift standard library files to you app’s package (aka bundle) and Apple requires Code Signing for non-Debug builds. The part that’s tricky is you will need to set a “Code Signing Identity” for the Release (and any AdHoc) configurations in the sub-project’s Build Settings. It’s not sufficient to have Code Signing configured properly in your own project. Getting this right is particularly important if you use a Continuous Integration server to automate builds and upload to HockeyApp or a similar AdHoc distribution service.
Troubleshooting Swift Build Issues
dyld: Library not loaded: @rpath/libswiftCore.dylib Referenced from: /Users/username/Library/Developer/Xcode/DerivedData/Path/To/Framework Reason: image not found
If you get that error message when build it means you forgot to enable “Embedded Content Contains Swift Code” as described above.
Crashes when running your application on an actual device? You probably have something in Code Signing mis-configured. Check out this page for some additional details.
fatal error: module 'MyLibrary' not found @import MyLibrary; ~~~~~~~^~~~~~ 1 error generated.
We got this error on our build server during compilation, but the project built just fine locally. The error literally meant that the compiler could not find the framework module. Turns out that since we use an extra Configuration/Scheme to have separate build settings for our AdHoc builds, the compiler could not find the .framework file, since xcodebuild places the build products in a folder prefixed with the Configuration/Scheme name (like debug-iphoneos.) To fix it we simply added a Configuration/Scheme with a matching name to the sub-project.
Be prepared to use Clean and Clean Build Folder commands more often than even a typical Xcode project. Even a stable Swift version (our module was using 1.2) seems to be glitchy when switching back and forth from simulator to device and clearing out previous build problems.
Conclusion: Using a Swift Library in an Objective-C project
With the advent of Swift 2.0 and the announced open-sourcing of the language, Swift will continue to gain momentum and you’ll be seeing more nice, useful frameworks that you might want to add to an existing project. A lot of developers are sticking with Objective-C for new projects but might be interested in a shiny new Swift module. Hopefully these tips will make it easier when that time comes.