With Xcode 9, it’s possible to mix and match Swift 3 and 4 libraries together. In the build settings for the project you set the version of Swift to use by configuring the SWIFT_VERSION
setting. You’re able to override the project setting at the target level, thereby building some targets with Swift 3, and others with Swift 4.
If you’re using CocoaPods as your dependancy manager, there’s an issue when mixing and matching.
As you know, when using CocoaPods, you end up with an Xcode workspace that contains your main project, and a Pods project. Whenever you run pod install
or pod update
, CocoaPods will set the SWIFT_VERSION
for all targets to be whatever your main project is set to, or it will fallback to Swift 3 if the main project doesn’t have the SWIFT_VERSION
specified.
This means Xcode will try and compile all targets with the same version of Swift, regardless of what version of Swift is actually needed. There’s no built-in way for you to specify the version of Swift to use for each pod you’re including. There is a way for the pod maintainer to specify the version needed in the podspec (they need to set pod_target_xcconfig = { 'SWIFT_VERSION' => '4.0' }
see XCGLogger.podspec for an example), but I’ve found it’s rare at this time for it to be set (hopefully this post will help change that).
Even if the pod sets the version of Swift to use, we run into a problem when Xcode resolves the setting. Xcode will prefer the target’s direct setting over the podspec’s suggestion, and since pod update
always sets a direct setting on the target, the pod spec’s suggestion is never used (not surprising it’s rarely set).
The solution is to add a post_install
script to the end of your podfile:
Let's examine this script.
It’s a post_install
script so CocoaPods will execute the script after is has updated all of the included pods and updated the project file.
The script starts by looping through the build configurations of the Pod project and sets the default Swift version to 4.0 (lines 2-5).
Then it loops through all of the project’s targets (lines 7-19). It checks the target name against a known list of targets (line 8) and sets each of the configurations for matching targets to Swift 3 (lines 10-12). If the target isn’t in the known list, the script unsets the Swift version (lines 15-17), which will allow the pod to set the version itself using the pod_target_xcconfig
setting we noted above. If the pod doesn’t set the version, Xcode will use the default Swift version we set at the start.
You will need to tweak the script for your project, specifically to set your default Swift version, and then to add the targets that require a different version on line 8.
If you’ve found this article helpful, please subscribe to the RSS feed and follow me on Twitter
It would be awesome if you’d download our new app All the Rings. It’s free and we really think you’ll like it!
If you see any errors, want to suggest an improvement, or have any other comments, please let me know.