CocoaPods and Multiple Swift Versions

When a new version of Swift releases, 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 fix it ASAP, etc. But you can fix it easily yourself.

20 September 2018
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.

The Issue

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.

Manual Fix

  • 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!

Script Fix

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

For each 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, which also works:

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.


by:
David Lari

https://davidlari.com
Interests: programming, writing, science, history. You might also find me playing some PC Games.