Swift 4 Migration with CocoaPods

Overview

Recently I worked on migrating my code to Swift 4. This proved to be more of a challenge than I originally anticipated. Although according to Apple "Xcode 9.0 comes with a Swift Migrator tool that helps you migrate your project to Swift 4", this process wasn't as straight forward as one might expect. In this post I'll be walking through some tips, tricks, and best practices about how I converted cclipss to Swift 4.

Why Swift 4?

The following are all changes, improvements, and/or additions in Swift 4, click here for a full guide about What's New in Swift 4.

  • Strings
  • Dictionary and Set
  • Private Access Modifier
  • Key-Value Coding
  • Multi-line String Literals
  • One-Sided Ranges
  • Limiting @objc Inference

Guide

Quick note before we get started, in order for this to work your project has to be fully functional and working on Swift 3 with no errors or issues.

Step 0 - New Git Branch

Although not required I would highly encourage to create a new branch or some way to track changes in case things go wrong you can revert back to a working version. Committing often throughout this process is very important and helpful. As well as building your application and solving errors right after they happen instead of moving on to next steps is very helpful.

Step 1 - Update the Podfile

Add the following to your Podfile and then run pod install.

post_install do |installer|
  installer.pods_project.targets.each do |target|
    target.build_configurations.each do |config|
      config.build_settings['SWIFT_VERSION'] = '3.2'
    end
  end
end

Step 2 - Convert the project

From Xcode 9 click Edit -> Convert -> Convert to current swift syntax. Because cclipss has many targets such as a share extension and an iMessage App I did each target seperatly and commited after each one was working incase things went wrong. Only convert your targets, do not convert CocoaPod targets.

Step 3 - Solve Errors

I ran into a few errors while converting the project. For example after converting this code was giving me an error.

var multipleAttributes = [String : Any]()
multipleAttributes[NSAttributedStringKey.foregroundColor] = UIColor.init(red: 0.25, green: 0.25, blue: 0.25, alpha: 1.0)

Changing var multipleAttributes = [String : Any]() to var multipleAttributes = [NSAttributedStringKey : Any]() solved that problem.

At this point I was experiencing this problem in Xcode (see my Stack Overflow question, that I solved right after posting). Xcode was giving random errors about code that should never be run in the iMessage App. In reality the problem was the error I mentioned above. If you have random errors that don't make any sense I would suggest cleaning your project and restarting Xcode, then trying to build again. (seems like a bug with Xcode maybe)

Another problem I noticed while testing my app during runtime is that Xcode didn't put @objc in front of one of my Swift functions which caused problems. This was due to using a #selector with that function and it not using the @objc syntax.

Although those were all the errors I ran into I'm sure others exist so be sure to test your application thoroughly after converting to Swift 4.

Step 4 - Swift 3 @objc Inference Set to Default

After testing my application thoroughly at runtime I changed Swift 3 @objc Inference from On to Default in the project build settings. This removed the warning displayed at build time. Before turning this to Default be sure to test at runtime to ensure Xcode added all of the correct @objc syntax where needed.

Step 5 - Update the pods

Now time to check what pods are already converted to Swift 4 and which aren't.

Remove the code we added earlier to the Podfile and then run pod install.

If you are lucky all your pods are already available in Swift 4 and the project should compile and be good to go.

If when building the project, some pods fail to compile, go to the pod github page and check if it’s converted to Swift 4.

If it’s already been converted, click on your Pods project, select the target that fails to compile, go to build settings and make sure the Swift Language Version is set to Swift 4.

If it's not been converted add the following code to your Podfile.

post_install do |installer|
        installer.pods_project.targets.each do |target|
            if ['POD1', 'POD2', 'POD3'].include? target.name
                target.build_configurations.each do |config|
                    config.build_settings['SWIFT_VERSION'] = '3.2'
                end
            end
        end
   end

Now replace POD1, 2, and 3 with all the pods that aren't compatible with Swift 4 (removing or adding items as necessary).

Step 6 - Final Test

Make sure to test your application and ensure everything is working. The more testing you can do throughout this process the better.

Hopefully this helped get you started with Swift 4 conversation and answered some questions.