A Guide to Swift 3 Migration for iOS App

The Apple-introduced Swift programming language has become very popular among developers. Swift was quickly adopted by iOS and iPhone application development companies, for its speed and efficiency. Since attaining open source status in December 2015, Swift has made an eventful journey to version 3.0.

The first official preview branch of Swift 3.0 was released at WWDC, bundled with Xcode 8 for iOS 10.x . The biggest change that 3.0 brings is a rewrite of the APIs. The intention was to make many different frameworks more Swift-like. Which also means that a lot of Swift 2.2 and lower code will have many errors when you first open old projects. Thankfully, there’s a migration tool in Xcode 8. When we ran the tool on some of our Swift 2.2 code, we were able to update a part of the code without much trouble.

 

Who really needs to migrate to Swift 2.3 or Swift 3.0 ?

Swift language is a new player in the market. That is why Apple seems to be trying to mitigate its immaturity by probably making Swift 3.0 the last version with (major) breaking changes.

The question is, should you upgrade to 2.3 or 3.0? If you have a significant Swift code base, then you need to migrate to Swift 2.3 first and then to Swift 3.0. If your Swift codebase isn’t massive, then you should skip 2.3 and jump to 3.0.

 

Pre-migration preparation

For effective migration process it’s really important to make sure that the project you want to migrate builds successfully and all its tests pass, after compiling it on Xcode 7.3. Project needs to be managed under source control to verify, modify or to discard changes done in the migration process.

Dependencies are important. Make sure to check if your dependencies support Swift 3.0. Most of the major Swift libraries/frameworks support are available now. Remember that the 3.0 upgrade is irreversible, which means that code conversion to Swift 2.x is not possible.

Projects having dependency on other open source projects and private cocoapods should update those first. Below are steps for the same:

    • >   Delete Pods folder from project directory.
    • >   Open Terminal > go to Project Directory > Enter command: sudo gem install cocoapods or update your cocoapods.
    • >   Do the necessary versionx updates in pod file and save it.
    • >   Enter command: pod install.

 

Migration process

People who have been through the Swift migration process might know that the Xcode provides a tool to convert syntax automatically, which will usually get you maximum of the migration processes done successfully. The remaining part can be manually fixed, before your project is built.

Automatic conversion by Xcode is a great place to start, which will handle most of the easy changes for you. You should, of course, review these changes and ensure none of the underlying logic is modified.

 

 

 

 

Migration Steps

1) Initiating Migration process using Xcode 8+ migration tool

Apple has included a Migration Assistant with Xcode 8 OR Xcode 8.0 comes with a Swift Migrator tool that helps you migrate your project to Swift 3, or update it to work with Swift 2.3 and the new SDKs.

Swift_1

 

When you open your project with Xcode 8.x for the first time, you will be prompted via migration assistant to do a migration pass. The assistant can also be invoked manually from the menu Edit -> Convert -> To Current Swift Syntax…

Use Swift 2.3 OR Use Swift 3

After you invoke the migration assistant and you select “Use Swift 2.3” or “Use Swift 3”, you will be presented with a list of targets to migrate. Targets that do not contain any Swift code will not be selected.

 

 

Swift_2 Swift_3

Clicking ‘Next’ will bring up the ‘Generate Preview’ sheet and the assistant will initiate a migration ‘build’ to get source changes. When this is done, you will be presented with all the changes that will be applied once you click ‘Save’. Note that in the diff view, the original source (before conversion) is on the right and the changes are on the left. Clicking ‘Save’ will apply the source changes to the original files. If you choose moving to Swift 2.3, the targets will have the “Use Legacy Swift” build setting set.

 

2) Wait until the upstream open-source project updates to Swift 2.3 or Swift 3

Swift_4 Swift_5

There may have been issues with processing the targets that will negatively impact the migration process. Switch to the “Report Navigator” and select the ‘Convert’ entry that was added; this is the conversion build log. Check the log for errors that may have showed up.

If you see errors about not being able to code-sign the target, try disabling code-signing from the build settings of the target. If you see other errors, please file a bug report at https://bugreport.apple.com and include the details.

Errors Screen after Conversion:

Swift_6

There have been many significant changes for Swift 3, which the migrator will help you with. You can see an overview of the Swift 3 evolution proposals here: https://github.com/apple/swift-evolution

 

Here are some common types of automatic conversions that Xcode will provide for you:

1: Underscores in method signatures

func foo(bar: Int) => func foo(_ bar: Int)

2: Private becomes fileprivate:

All your declarations that were formerly private will now be fileprivate which is the new keyword that behaves exactly as private did previously, restricting access to the current file. The new private allows access only within the current declaration, restricting access (more restrictions than before).

3: Grand Transition Renaming

The NS (NextStep!) prefix has been removed from the vast majority of APIs and many singleton-like patterns (sharedX, defaultY, etc) are no longer methods but properties. In addition, what used to be sharedManager or sharedApplication is now just shared.

4: Multiple unwrapping conditionals

// this won’t work in Swift 3

if let x = optionallyGetX(), y = optionallyGetY() { … }

// much better

`if let x = optionallyGetX(), let y = optionallyGetY() { … }`

5: Conditions no longer contain where

// previously

if let x = optionallyGetX() where x == true

// now, just commas

if let x = optionallyGetX(), x == true

Note: One note from an item that was not converted: Your Swift strings are still String and their Objective-C counterparts are still NSString because they’re distinct and removing the NS prefix would obviously cause some weird collisions.

 

Migration: Temporary Troubles

The process of migration can be really frustrating when you keep on compiling your code and encountering an unending list of errors. We spent weeks migrating our codebase. But believe me, watching our code build successfully after so much of efforts and patience, was a great feeling. The Swift 3.0 update has led to many issues in the migration process but this seems a promising upgrade towards making programming Fast, Efficient and Easy

Happy Migration 🙂