What’s New in Swift 3?

Check out what’s new in Swift 3 – Swift’s first major release as an open source project. By Ben Morrow.

Login to leave a rating/review
Save for later

Update 10/3/16: This tutorial has been updated for Xcode 8 and Swift 3.

Swift 3 arrived on September 13, 2016, and brought major code changes to all Swift developers.

If you haven’t been following the Swift Evolution project closely, you may wonder what changes are in store, how it will affect your code, and when you should start porting your code to Swift 3. This article is for you! :]

In this article, I’ll highlight the most significant changes in Swift 3 that will impact your code. Let’s dive in!

Getting Started

Swift 3 is now available in Xcode 8. To allow developers to make the migration to Swift 3 on their own terms, Apple has included Swift 2.3 as a minor update bundled with Xcode 8. To you as a developer, Swift 2.3 is the same as Swift 2.2 but with support for many of the new SDKs and Xcode features announced at WWDC. You can submit to the App Store using Swift 2.3 if you have not yet migrated your code to Swift 3.

I recommend trying out the features we discuss in a playground and maybe even running the Migration Assistant on one of your projects so you can get a feel for everything that is changing.

Migrating to Swift 3

When converting to Swift 3, you’ll notice that practically every file needs changes! That’s largely because, all the Cocoa API names have changed. Or to be more precise, the API is the same, but there’s one name appropriate for Objective-C and one name appropriate for Swift. Swift 3 is going to make Swift much more natural to write in the years ahead.

Apple has included a Migration Assistant with Xcode 8 that can brilliantly make most of these changes in one fell swoop. Don’t be surprised though if you need to touch up a few areas yourself that the migrator doesn’t handle automatically.

You can convert to either Swift 2.3 or Swift 3 immediately. If you ever need to bring it back up, you can always navigate in Xcode to Edit > Convert > To Current Swift Syntax…. The compiler fortunately shares the same smarts as the Migration Assistant as well. If you accidentally use the old API on a method call, the compiler will offer a Fix-It option that will help you use the correct modern API.

Implemented Swift Evolution Proposals

Community members submitted over 100 proposals for changes to Swift since it went open source. A large number of them (70 so far) have been accepted after discussion and modification. Those that have been rejected have sparked some intense discussion as well. In the end however, the core team makes the final decision on all proposals.

The collaboration between the core team and the wider community has been impressive. In fact, Swift has garnered 30 thousand stars on Github. Several new proposals are submitted every week, week-after-week. Even Apple engineers pen proposals on open Github repository when they want to make changes.

In the sections below, you’ll see linked tags such as [SE-0001]. These are Swift Evolution proposal numbers. The links to each proposal have been included so you can discover the full details of each particular change. You can also check the status of all Swift Evolution proposals to see which ones have been implemented. The code examples below build on Paul Hudson’s excellent overview of the common changes you’ll notice in Swift 3.

API Changes

The biggest update in Swift 3 involves the standard library adopting consistent naming conventions across libraries. The API Design Guidleines contain the rules that the team settled on as they were building Swift 3, which place a high value on readability and accessibility to new programmers. The core team operated on the principal that “Good API design always considers the call site”. They strove to bring clarity to the point of use. Without further ado, here are the changes most likely to impact you.

Consistent First Argument Labels

Let’s start off strong with a direct reversal of a practice you use every day in Swift.


The first parameter in functions and methods now always has a label unless you request otherwise. Previously when you called a function or method you omitted the first parameter label [SE-0046]:

// old way, Swift 2, followed by new way, Swift 3

NSJSONSerialization.JSONObjectWithData(data, options: [])
JSONSerialization.jsonObject(with: data, options: [])

addQuadCurveToPoint(endPoint, controlPoint: controlPoint)
addQuadCurve(to: endPoint, controlPoint: controlPoint)

NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)

panelView.centerXAnchor.constraint(equalTo: view.centerXAnchor)

array.remove(at: 3)

pngImageData.writeToURL(fileURL, atomically: false)
pngImageData.write(to: fileURL, options: [])

numberOfSections(in: tableView)

SCNAction.moveTo(SCNVector3Make(1, 1, 1), duration: 1)
SCNAction.move(to: SCNVector3(1, 1, 1), duration: 1)

Take note of how the method definitions use prepositions like “of”, “to”, “with”, and ” in” for the external name. These are part of an effort to optimize readability.

If the method call reads well without a preposition and doesn’t need a label, you should explicitly exclude the first parameter name with an underscore:

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { ... }
override func didMoveToView(_ view: SKView) { ... }

In many programming languages, methods may share a base name and offer different parameter names. Swift is no exception, and now you’ll come across overloaded method names much more since the APIs have been translated to be more direct. Here’s an example with two forms of index():

let names = ["Anna", "Barbara"]
if let annaIndex = names.index(of: "Anna") {
  print("Barbara's position: \(names.index(after: annaIndex))")

Altogether, the parameter name changes make method naming more consistent and easier to learn.

Omit Needless Words

In previous iterations of Apple libraries, method names indicated their return value and parameter names included the name of the type they expected. Because of the Swift compiler’s type checking, this is much less necessary. The team took a hard look at how to filter out all the noise so that only the signal remains and thus a lot of word repetition has been removed.


The API has gotten smarter about how Objective-C libraries are transformed into native Swift [SE-0005]:

// old way, Swift 2, followed by new way, Swift 3





animals.insert("Koala", atIndex: 0)
animals.insert("Koala", at: 0)



Modernized GCD and Core Graphics

Speaking of old API holdouts, GCD and Core Graphics have both received a much-needed makeover.


Grand Central Dispatch is used for many threading tasks such as long calculations or to communicate with a server. By moving activity to a different thread, you prevent locking up the user interface. The libdispatch library was written in the C programming language and has always used a C style API. The API has now been reimagined in native Swift [SE-0088]:

// old way, Swift 2
let queue = dispatch_queue_create("com.test.myqueue", nil)
dispatch_async(queue) {
    print("Hello World")

// new way, Swift 3
let queue = DispatchQueue(label: "com.test.myqueue")
queue.async {
  print("Hello World")

Similarly, Core Graphics was written in C and in the past used awkward function calls. Here’s how the new way looks [SE-0044]:

// old way, Swift 2
let context = UIGraphicsGetCurrentContext()
let startAngle: CGFloat = 0.0
let endAngle = CGFloat(2 * M_PI)
let strokeWidth: CGFloat = 1.0
let radius = self.frame.midX - strokeWidth
let center = CGPointMake(self.frame.midX, self.frame.midY)
CGContextSetStrokeColorWithColor(context, UIColor.redColor().CGColor)
CGContextSetLineWidth(context, strokeWidth)
CGContextAddArc(context, center.x, center.y, radius, startAngle, endAngle, 0)
CGContextDrawPath(context, kCGPathStroke)

// new way, Swift 3
guard let context = UIGraphicsGetCurrentContext() else {
let startAngle: CGFloat = 0.0
let endAngle = 2 * CGFloat.pi
let strokeWidth: CGFloat = 1.0
let center = CGPoint(x: self.frame.midX, y: self.frame.midY)
let radius = self.frame.midX - strokeWidth
context.addArc(center: center,
               radius: radius,
               startAngle: startAngle,
               endAngle: endAngle,
               clockwise: false)
context.drawPath(using: .stroke)

Capitalization on Enumeration Cases

In another reversal from the way you’ve been used to coding Swift, lowerCamelCase now replaces UpperCamelCase for enumeration cases. This makes them more consistent with other properties – or values [SE-0006]:

// old way, Swift 2, followed by new way, Swift 3




UpperCamelCase is now reserved solely for names of types and protocols. While this may take some getting used to, the Swift team had really good reasoning in their strive for consistency.

Methods that Return or Modify

The standard library is also getting more consistent in method naming. You choose a name based on the side effects or the actions taken. The rule of thumb is that if it includes a suffix like “-ed” or “-ing” then think of the method as a noun. A noun method returns a value. If it doesn’t have the suffix, then it is most likely an imperative verb. These “verb” methods perform the action on referenced memory. This is also known as modifying in place. There are several pairs of methods that follow this noun/verb convention in the standard library. Arrays showcase the trend well. You can use enumerate()/enumerated(), reverse()/reversed(), and sort()/sorted(). Previously sort() was known as sortInPlace(). The verbs modify the original array and the “-ed” nouns return a copy of the array. Here’s a snippet of those methods in action [SE-0006]:

var ages = [21, 10, 2] // variable, not constant, so you can modify it
ages.sort() // modified in place, value now [2, 10, 21]

for (index, age) in ages.enumerated() { // copied into a dictionarry
  print("\(index). \(age)") // 1. 2 \n 2. 10 \n 3. 21

Function Types

Function declarations and function calls have always required parentheses around their parameters:

func f(a: Int) { ... }


However, when you use a function type as a parameter itself, you might write something like this:

func g(a: Int -> Int) -> Int -> Int  { ... } // old way, Swift 2

You probably notice that it’s fairly difficult to read. Where do the parameters end and the return types begin? With Swift 3 the correct way to define this function is [SE-0066]:

func g(a: (Int) -> Int) -> (Int) -> Int  { ... } // new way, Swift 3

Now the parameter lists are surrounded by parentheses and followed by the return type. Things are clearer, and consequently, the function type is easier to recognize. Here’s a more robust comparison:

// old way, Swift 2
Int -> Float
String -> Int
T -> U
Int -> Float -> String

// new way, Swift 3
(Int) -> Float
(String) -> Int
(T) -> U
(Int) -> (Float) -> String

API Additions

While the biggest update to Swift 3 has been the modernization of the existing APIs, there is much more the Swift community has been hard at work at – including several useful additions to the Swift API as well.

Accessing the Containing Type

When you define a static property or method, you have always called them on the type directly:


If you are writing code in the context of a type, you still need to include the name of the type to call a static method on the type. To make this a bit cleaner, you can now call Self to get the containing type. The capital ‘S’ refers to the type of self, whereas the lowercase ‘s’ refers to the instance of self.
Here’s how it works in action [SE-0068]:

struct CustomStruct {          
 static func staticMethod() { ... }          
 func instanceMethod() {          
 Self.staticMethod() // in the body of the type          
let customStruct = CustomStruct()          
customStruct.Self.staticMethod() // on an instance of the type          

Note:This feature will be added after Swift 3.1, but it is not currently available in Xcode 8.

Inline Sequences

sequence(first:next:) and sequence(state:next:) are global functions that return infinite sequences. You give them an initial value or a mutable state and they will lazily apply a closure [SE-0094]:

for view in sequence(first: someView, next: { $0.superview }) {
    // someView, someView.superview, someView.superview.superview, ...

You can constrain the sequence by using the prefix manipulator [SE-0045]:

for x in sequence(first: 0.1, next: { $0 * 2 }).prefix(while: { $0 < 4 }) { 
  // 0.1, 0.2, 0.4, 0.8, 1.6, 3.2

Note:This feature is added to Swift 3.1, but it is not currently available in Xcode 8.

Miscellaneous Odds and Ends

  • #keyPath() works like #selector() and helps you vanquish typos in stringly typed APIs
  • You now call pi on the type you intend to use it as: Float.pi, CGFloat.pi. And most of the time the compiler can infer the type: let circumference = 2 * .pi * radius [SE-0067]
  • The NS prefix has been removed on old foundation types, you can now use Calendar, Date instead of NSCalendar and NSDate.

Improvements to Tooling

Swift is a language, and a large part of writing it involves using a development environment - which for Apple developers is likely Xcode! The changes going on with the tooling will impact how you write Swift every day.

Swift 3 fixes bugs in the compiler and IDE features. It also improves the precision of error and warning messages. And as you might expect, with each release, Swift is getting faster in how it runs and compiles:

  • By improving string hashing there was a 3x speedup in dictionaries of strings
  • By moving objects from the heap to the stack there was a 24x speedup (in some cases)
  • The compiler now caches multiple files at once (when doing whole module optimization)
  • Code size optimization has reduced the compiled size of Swift code. Apple's demo Demobots reduced the compiled size to 77% of the original

Xcode is also learning how to think in native Swift:

  • When you right-click on an API method like sort() and jump to its definition, you used to be taken to a cryptic header file. Now, in Xcode 8, you see that sort() is an extension to Array like you would expect.
  • Swift Snapshots are like the nightly releases of Swift Evolution. They offer a chance to work with the new syntax before its fully baked into Xcode. Xcode 8 can load and run Swift Snapshots in playgrounds.

The Swift Package Manager

Open source Swift is actually a family of repositories including the language, the core libraries, and the package manager. Together, this suite makes up what we think of as Swift. The Swift Package Manager defines a simple directory structure for any Swift code that you share and import into projects.

Similar to package managers you may be used to such as Cocoapods or Carthage, Swift's package manager will download dependencies, compile them, and link them together to create libraries and executables. Swift 3 is the first release to include the Swift Package Manager. There are 1,000 libraries that already support it. The Swift Package Manager is presently mainly used for server code projects and does not yet support iOS projects in Xcode.

Planned Future Features

The core team aimed for Swift 3 to let you keep your code from version to version in the future by striving to avoid breaking changes and offering long deprecation cycles. That goal was nearly reached, but the point releases on the way to Swift 4 will have a few more changes this year.

There were also some loftier, related goals that weren't reached for this release, namely generics additions and Application Binary Interface (ABI) stability.

The generics additions will include recursive protocol constraints and the ability to make a constrained extension conform to a new protocol (i.e., an array of Equatable elements is Equatable). Swift can't declare ABI stability until these features are complete.

ABI stabilization will allow applications and libraries compiled with different versions of Swift to be able to be linked and interact with each other. This is a vital step for third party libraries to ship frameworks without providing the source code. Right now, new versions of Swift not only require them to update their code, but to rebuild their frameworks as well.

Additionally, ABI stability would remove the need to ship the Swift standard library along with binaries, as is currently the case with iOS and macOS apps created with Xcode. Right now binaries are bundled with 2 MB extra filesize that ensures that they will run on future operating systems.

Where to Go From Here?

Swift continues to evolve as the community converges on best practices. While still in its infancy, the language has a lot of momentum and a big future. Swift already runs on Linux, and you will likely see it running on servers in addition to devices in the coming years. Designing a language from scratch certainly has its advantages as opportunities to break ABI stability once it's locked down will be rare. This is a unique chance to get the language correct without regrets.

Swift is also expanding its reach. Apple is eating their own dogfood. Teams at Apple use Swift on the Music app, Console, picture-in-picture in Sierra, the Xcode Documentation viewer, and the new Swift Playgrounds app for iPad.

Speaking of which, there's a big push to get non-programmers learning Swift, both on the iPad and through education initiatives.

The takeaway here is that Swift continues its ascent: the names are better, the code reads clearer, and you have the tools to migrate. If you're inspired to dig deeper, you can watch the WWDC session videos.

There will surely be more to come in the journey to Swift 4. We’ll be staying on top of all the updates here, so keep an eye out for tutorials, book announcements, and videos as we start using the exciting changes.

What parts of Swift 3 are you most excited about? What would you like us to cover? Let us know in the comments below!