Migrating to Swift 3

This is a legacy document for Xcode 8 and migrating from Swift 2.

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.

Pre-Migration Preparation

To get the most effective migration, make sure that the project that you intend to migrate builds successfully, and all its tests pass, when using Xcode 7.3[.1]. Also make sure that the project is managed under source control. This will allow you to easily review the changes that were applied via the migration assistant and to discard them and re-try the migration if needed.

If you have multiple schemes that build different independent products (or the same product for different platforms) it is important to create one scheme that builds everything in your project and for all the platforms you need, including your unit test targets. The migration assistant does a migrator “build” to gather the changes, using the scheme you have selected, so the targets that will get processed are the ones that are included in the scheme. To review and modify what is included in the scheme, invoke the “Edit Scheme…” sheet and select the “Build” tab from the column on the left, and make sure all your targets and their unit tests are included.

If your project depends on other open-source projects that are provided by Carthage or CocoaPods, consult the Using Carthage/CocoaPods Projects section.

Swift Migration Assistant

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

You can choose from two kinds of migration to perform:

Optionally, you can move to Swift 2.3 now and invoke the migration assistant again later to update to 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.

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 on ‘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 chose to move to Swift 2.3, the targets will have the “Use Legacy Swift” build setting set.

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.

If you need to apply any workarounds, discard the changes that you accepted from the migration assistant earlier, apply the workarounds, and invoke the assistant manually to re-try the conversion from the start.

Swift 3 Migration Changes Overview

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/swiftlang/swift-evolution

Here is a brief overview of the more impactful source-breaking changes:

API Design Guidelines

The Objective-C APIs are imported into Swift 3 according to the new Swift API design guidelines. This affects both how the SDKs are imported and the Objective-C user frameworks. The Swift Standard Library also has many changes for adhering to the guidelines. For more details you can refer to proposal SE-0005 - Better Translation of Objective-C APIs Into Swift. The migrator is lowercasing enums declared by the user, to match them with the new guidelines.

SDK

Certain frameworks like CoreGraphics and Dispatch, and other types from Foundation, are no longer getting imported as a set of global functions and variables but as member functions and properties on the respective Swift types. For details see proposals SE-0044 - Import as member, SE-0088 - Modernize libdispatch for Swift 3 naming conventions.

The ‘NS’ prefix from key Foundation types is getting removed in Swift 3, see SE-0086 - Drop NS Prefix in Swift Foundation.

Swift Standard Library

The Collection indexing model has changed dramatically in Swift 3, for more details see SE-0065 - A New Model for Collections and Indices. The most visible change is that indexes no longer have successor(), predecessor(), advancedBy(_:), advancedBy(_:limit:), or distanceTo(_:) methods. Instead, those operations are moved to the collection, which is now responsible for incrementing and decrementing its indices.

myIndex.successor()  =>  myCollection.index(after: myIndex)
myIndex.predecessor()  =>  myCollection.index(before: myIndex)
myIndex.advance(by: …) => myCollection.index(myIndex, offsetBy: …)

If the migrator does not know the collection responsible for the indices, it will insert an editor placeholder that you must fill with your collection.

In support of the collections changes, Range types also had some changes. Previously x..<y and x...y produced the same type, Range<T>. Now these expressions can produce one of the four types: Range, CountableRange, ClosedRange, CountableClosedRange. We split Range into Range and ClosedRange types to allow closed ranges that include the maximum value of the type (for example, 0...Int8.max works now). The plain range types and their ~Countable counterparts differ in the capabilities:

The ..< and ... operators try to do the right thing and return the most capable range, so that code like for i in 1..<10 infers a CountableRange and continues to work. If you have a variable that is typed as one range type, and you need to pass it to an API that accepts a different type, use the initializers on range types to convert:

var r = 0..<10 // CountableRange<Int>
Range(r) // converts to Range<Int>

Language

After Migration

While the migrator will take care of many mechanical changes for you, it is likely that you will need to make more manual changes to be able to build the project after applying the migrator changes.

You may see compiler errors that have associated fixits; while the migrator is designed to incorporate fixits that the Swift 3 compiler provides, it is a known limitation that this is not guaranteed to work 100% (particularly when you have inter-dependencies between targets) and some fixits may be missed.

Even if it compiles fine, the code that the migrator provided may not be ‘ideal’, for example you may see casts to ‘NS’ prefixed types (url as NSRL), that would be better if the code was restructured to use related APIs on the new URL value type instead. You may also see new comments that the migrator added (/*Migrator FIXME: ...*/) where it provides a hint on how to convert the code better.

See Known Migration Issues section, for a list of issues that you may encounter while trying to migrate your project.

Using Carthage/CocoaPods Projects

If you are using binary Swift modules from other projects that are not built along with your project in your Xcode workspace, you can choose from one of the following migration strategies:

Known Migration Issues

Swift Standard Library

SDK

static let MyGreatNotification = Notification.Name("MyGreatNotification")

// Use site (no change)
NotificationCenter.default().post(name: MyController.MyGreatNotification, object: self)'

Swift 3 Language

Miscellaneous