About a 3 minute read.
When a new version of Xcode/Swift is released, I see a flurry of activity on Github related to people posting issues that they can’t compile so-and-so library anymore, can the maintainer please hurry up and update to the latest language ASAP, etc.
Here’s the issue and the fix.
Xcode’s Swift compiler can compile to more than one version of Swift. The compiler can handle having a pod that is compiled in Swift 3, another in Swift 4 and yet others in Swift 4.2. (As of this writing, Xcode 10 with support for Swift 4.2 is the latest release).
The problem with Cocoapods is that it will inherit the Swift version of the main project. So once you convert your source code to 4.2 for example, the next time you
pod update, all your pods will have their Swift language version set to 4.2 also. But if some of the pods have not been updated to the latest syntax, they may not compile in Swift 4.2. But all is not lost! You can simply tell Xcode to compile those specific pods in Swift 4.
Here’s how to fix it.
- After you
pod install, reopen your workspace, then click on the Pods project on the Navigator.
- Select Build Settings, making sure that filters are set to All, Combined, then type swift lang in the search box.
- For each pod, select the correct Swift Language Version from the drop down. For example, after updating to Swift 4.2, I have to manually change some pods to Swift 4 if they have not yet been updated.
The downside to this fix is that you must repeat the manual process every time you
pod update. Or you could make a script to do it!
The other way to fix it is to add a post install script on your pod file. At the bottom of the file, just add some Ruby code:
post_install do |installer| installer.pods_project.targets.each do |target| if target.name == 'SomePod' || target.name == 'SomeOtherPod' || target.name == 'YetAnotherPod' target.build_configurations.each do |config| config.build_settings['SWIFT_VERSION'] = '4.0' end end end end
target.name, it will set the Swift version to 4.0. As maintainers update their pods to 4.2, I simply remove the
target.name == 'podname' from the script for that pod.
If you don’t want a whole bunch of these ‘or’ conditions, you could use this code, I think, but I haven’t tested it yet:
post_install do |installer| installer.pods_project.targets.each do |target| if ['SomePod', 'SomeOtherPod', 'YetAnotherPod'].include? target.name target.build_configurations.each do |config| config.build_settings['SWIFT_VERSION'] = '4.0' end end end end
Why Isn’t It Automagically Doing This?
Why doesn’t Cocoapods support some kind of version setting? Well, the problem is that Apple have been changing Xcode quite a bit between versions. So, a solution for Xcode 7 would have been broken in Xcode 8, for example (based on my understanding of issues threads I’ve read on Github). Things seem to be settling down a bit. Apple have set some precedents and it looks like the Cocoapods team may address this in version 1.7. However, that will be awhile as version 1.6 is currently in beta as I write this.
In the meantime, I suggest the script above.