What's new in Swift?

Learn what's new in Swift with hands-on code examples, all in one place and with no clutter.

Questions? Feedback? Tweet me @twostraws.

New in Swift 1.1

countElements() is now count()

In Swift 1.0 you would count an array like this:

let items = [1, 2, 3]
println(countElements(items))

The countElements() function has been renamed to count() in Swift 1.1, so the new code is this:

let items = [1, 2, 3]
println(count(items))

macOS apps can now use @NSApplicationMain

iOS apps have a @UIApplicationMain attribute that automatically generates a UIApplicationMain() func to bootstrap the app. This is now also available to macOS developers using @NSApplicationMain, and this attribute will automatically be added to Cocoa app delegates in all new projects.

New in Swift 1.2

The zip() function joins two sequences

If you have two sequences that you'd like to join together, the zip() function will do just that and return an array of tuples. For example:

let names = ["Sophie", "Charlotte", "John"]
let scores = [90, 92, 95]
let zipped = zip(names, scores)

That will output an array of the tuples ("Sophie", 90), ("Charlotte", 92), and ("John", 95).

The flatMap() method transforms optionals and arrays

The flatMap() method is designed to allow you to transform optionals and elements inside a collection while also decreasing the amount of containment that happens. For example, if you transform an optional in a way that will also return an optional, using map() would give you an optional optional (a double optional), whereas flatMap() is able to combine those two optionals into a single optioanl.

let lengthOfFirst = names.first.flatMap { count($0) }

Decreasing the amount of containment also makes flatMap() a simple way of converting multi-dimensional arrays into single-dimensional arrays:

[[1, 2], [3, 4], [5, 6]].flatMap { $0 }

There is no "map" operation there, so we're just left with the flattening behavior – that will result in a single array containing the value [1, 2, 3, 4, 5, 6].

Closures can now be marked @noescape

Closures are reference types, which means Swift must quietly add memory management calls when they are passed into functions. To avoid adding unwanted work, you can now mark closure parameters with the @noescape keyword, which tells Swift the closure will be used before the function returns – it doesn't need to retain or release the closure.

As an example, this function checks whether a password that we have stored matches a password the user just entered, but it does this using a closure so that you can give it any encryption code you like. This closure is used immediately inside the function, so @noescape may be used as a performance optimization:

func checkPassword(encryption: @noescape (String) -> ()) -> Bool {
    if closure(enteredPassword) == storedPassword {
        return true
    } else {
        return false
    }
}

Classes can now have static methods and properties

Swift 1.2 gives us an alias for class final properties: static. While class variables may be overridden in subclasses, static variables may not. For example:

class Student: Person {
    // THIS ISN'T ALLOWED
    override static var count: Int {
        return 150
    }

    // THIS IS ALLOWED
    override class var averageAge: Double {
        return 19.5
    }
}

In this usage, static var is merely an alias for final class var.

Constants no longer require immediate initialization

Constants may be set only once, but Swift 1.2 allows us to create constants without initializing them immediately. For example:

let username: String

if authenticated {
    username = fetchUsername()
} else {
    username = "Anonymous"
}

A new Set data structure

Swift 1.2 introduced a new Set type that works similarly to NSSet except with value semantics. Sets work similarly to arrays except they are not ordered and do not store any element more than once. For example:

var starships = Set()
starships.insert("Serenity")
starships.insert("Enterprise")
starships.insert("Executor")
starships.insert("Serenity")
starships.insert("Serenity")

Even though that code tries to insert Serenity three times, it will only be stored in the set once.

Implicit bridging has been reduced

Prior to Swift 1.2 bridging from Objective-C types to Swift types happened implicitly, meaning that you could use the two interchangeable. From Swift 1.2 onwards you must now use as to typecast these yourself. For example:

authenticateUser(yourNSString as String)

Multiple if let bindings

You may now place multiple if let bindings on a single line separated by a comma, rather than embed them in increasingly indented pyramids.

For example, previously you would write code like this:

if let user = loadUsername() {
    if let password = decryptPassword() {
        authenticate(user, password)
    }
}

As of Swift 1.2 you can write this:

if let user = loadUsername(), let password = decryptPassword() {
    authenticate(user, password)
}

Typecasting now includes as!

From Swift 1.2 onwards we have three ways of performing typecasts: as is used for typecasts that will always succeed (e.g. someString as NSString), as? is used for typecasts that might fail (e.g. someView as? UIImageView), and as! is used to force typecasts. If you use as! and you're wrong, your code will crash.

For example:

let submitButton = vw.viewWithTag(10) as! UIButton

New in Swift 2.0

try/catch

This is a common feature of other languages, but something notably missing from Swift – at least until now. I'm not going to wade into the larger debate about the merits of try/catch (trust me, this can cause major fights!), I'm just going to explain what it does and how you can use it once you install Xcode 7.

try/catch is a way of programming that means "try this thing, but if it fails do this other thing instead." Swift uses enums for error types so that it can ensure your error catching is exhaustive, just like with switch statements. So for example, you might define your error list something like this:

enum MyError: ErrorType {
    case UserError
    case NetworkError
    case DiscoverydError
}

Notice how my error type builds on the built-in ErrorType protocol; this is required.

Once you've defined the various errors you want to work with, it's time to introduce three new keywords: throws, try, do and catch.

First up, throws is a simple keyword that you add to your method to tell Swift it might fail. You put it right before where you put your method's return type, like this:

func doStuff() throws -> String {

Once that's done, you cannot call that method unless your code is written to handle any errors it throws – Xcode simply won't compile. When you want to throw an error from inside your methods, you just write throw followed by the type of error you want to throw, like this:

func doStuff() throws -> String {
    print("Do stuff 1")
    print("Do stuff 2")
    throw MyError.NetworkError

    return "Some return value"
}

The dummy print() calls are there so you can follow the program flow, as you'll see in a moment.

But first, on to the next keyword: try. This is placed before any call to a method that throws an error, like this:

try doStuff()

This literally writes into your code "I acknowledge that this code might fail," so it's effectively syntactic sugar to ensure safety. But even with that your code still won't compile, because you don't catch the errors: you need to use do and catch.

Catching errors has two forms: catching specific errors and catching all errors. You can mix and match, meaning your code can say "if the error is X, I want to handle it like this; all other errors should be handled this other way."

Here's a very basic example showing how to catch all errors:

do {
    try doStuff()
    print("Success")
} catch {
    print("An error occurred.")
}

If you remember, we made the doStuff() method print "Do stuff 1" then "Do stuff 2" before throwing a network error. So, what will happen is:

  • "Do stuff 1" will be printed
  • "Do stuff 2" will be printed
  • The NetworkError error will be thrown, immediately exiting the doStuff() method – its return statement will never be reached
  • Control will jump to the catch block
  • "An error occurred" will be printed

To be clear: in the code above, "Success" will never be printed – as soon as any try methods throw an error, execution stops and jumps to the catch block.

As I said, you can mix and match generic and specific catch blocks, but you do need to be sure that all possible errors are caught. For example, this will execute one chunk of code for NetworkError errors, and another chunk for all other errors:

do {
    try doStuff()
    print("Success")
} catch MyError.NetworkError {
    print("A network error occurred")
} catch {
    print("An error occurred")
}

Use the guard keyword for early returns

It's very common to place some conditional checks at the start of a method to ensure that various data is configured ready to go. For example, if a Submit button is tapped, you might want to check that the user has entered a username in your user interface. To do this, you'd use this code:

func submitTapped() {
    guard username.text.characters.count > 0 else {
        return
    }

    print("All good")
}

Using guard might not seem much different to using if, but with guard your intention is clearer: execution should not continue if your conditions are not met. Plus it has the advantage of being shorter and more readable, so guard is a real improvement, and I'm sure it will be adopted quickly.

There is one bonus to using guard that might make it even more useful to you: if you use it to unwrap any optionals, those unwrapped values stay around for you to use in the rest of your code block. For example:

guard let unwrappedName = userName else {
    return
}

print("Your username is \(unwrappedName)")

This is in comparison to a straight if statement, where the unwrapped value would be available only inside the if block, like this:

if let unwrappedName = userName {
    print("Your username is \(unwrappedName)")
} else {
    return
}

// this won't work – unwrappedName doesn't exist here!
print("Your username is \(unwrappedName)")

Measuring strings has changed again.

If you just read username.text.characters.count and did a double take, I don't blame you: Apple has changed how strings are measured yet again. What was countElements() became count(), and has now gone away entirely – and in fact if you try to use count() with a String you'll get an error.

Instead, you should access the characters property of your String, then call count on that. Or at least that's what you should do until Apple changes its mind again…

Use the defer keyword to delay work until your scope exits

Some languages have a concept of try/finally which lets you tell your app "no matter what happens, I want this code to be executed." Swift 2 introduces its own take on this requirement using the defer keyword: it means "I want this work to take place, but not just yet." In practice, this usually means the work will happen just before your method ends, but here's the cool thing: this will still happen if you throw an error.

First, a simple example:

override func viewDidLoad() {
    super.viewDidLoad()

    print("Checkpoint 1")
    doStuff()
    print("Checkpoint 4")
}

func doStuff() {
    print("Checkpoint 2")
    defer { print("Do clean up here") }
    print("Checkpoint 3")
}

If you run that, you'll see "Checkpoint 1", "Checkpoint 2", "Checkpoint 3", "Do clean up here", then "Checkpoint 4". So, even though the defer line appears before checkpoint 3, it gets executed after – it gets deferred until the method is about to end.

I put "Do clean up code here" in there because that's exactly what defer is good at: when you know you need to flush a cache, write out a file or whatever, and you want to make sure that code gets executed regardless of what path is taken through your method.

As I said, work you schedule with defer will execute no matter what route your code takes through your method, and that includes if you throw any errors. For example:

override func viewDidLoad() {
    super.viewDidLoad()

    print("Checkpoint 1")

    do {
        try doStuff()
    } catch {
        print("Error!")
    }

    print("Checkpoint 4")
}

func doStuff() throws {
    print("Checkpoint 2")
    defer { print("Do clean up here") }
    throw MyError.UserError
    print("Checkpoint 3")
}

As soon as doStuff() throws its error, the method is exited and at that point the deferred code is called.

Mutability warnings

This is a simple change that is going to go a long way to help code readability. As you know, Swift developers prefer declaring things as constants (using let) rather than variables (using var). But what if you made something a variable by accident? Or if you thought you might need to change it, then never do?

As of Xcode 7 and Swift 2, you'll get warnings in your code whenever you declare variables that never change – Xcode literally examines the way you use the variable and knows if you never change it.

Checking API availability

One regular problem that iOS developers hit is that we need to be careful when using new APIs – if you try and use UIStackView on iOS 8, for example, your app will crash. In the olden days, Objective C developers would write code like this:

NSClassFromString(@"UIAlertController") != nil

That means, "if the UIAlertController class exists," which was a way of checking if we were running on iOS 8 or later. But because Xcode didn't know that was our goal, it couldn't ensure we got things right. Well, this is fixed with Swift 2, because you can now write code like this:

if #available(iOS 9, *) {
    let stackView = UIStackView()
    // do stuff
}

The magic happens with #available: it will automatically check whether we are running on iOS 9 or later, and, if so, will run the code with the UIStackView. The * after "iOS 9" is there as a catch all for any future platforms that Apple introduces, and it's required.

So, #available is cool, but even better is the fact that you can give it an else block and, because Xcode now knows this block will only execute if the device is iOS 8 or earlier, it can warn you if you new APIs. For example, if you wrote something like this:

if #available(iOS 9, *) {
    // do cool iOS 9 stuff
} else {
    let stackView = UIStackView()
}

New in Swift 2.1

String interpolation can now include string literals

Using quote marks inside strings caused problems before Swift 2.1, which meant that using string literals inside string interpolation was also difficult. This has been fixed in Swift 2.1, so this kind of code works fine now:

print("Hello, \(username ?? "Anonymous")")

This means it's also possible to read dictionary keys using string interpolation, like this:

print("Hello, \(user["name"]!)")

New in Swift 2.2

++ and -- are deprecated

Swift 2.2 formally deprecates the ++ and -- operators, which means they still work but you'll get a warning when you use them. Deprecation is usually a first step towards removing something entirely, and in this case both of these operators will be removed in Swift 3.0.

In their place, you need to use += 1 and -= 1 instead. These operators have been there all along, and are not going away.

You might wonder why two long-standing operators are being removed, particularly when they exist in C, C#, Java, and – critically to its "joke" – C++. There are several answers, not least:

  1. Writing ++ rather than += 1 is hardly a dramatic time saving
  2. Although it's easy once you know it, ++ doesn't have an obvious meaning to people learning Swift, whereas += at least reads as "add and assign."
  3. C-style loops – one of the most common situations where ++ and -- were used – have also been deprecated, which brings me on to my next point…

Traditional C-style for loops are deprecated

Yes, you read that correctly: loops like the below will soon be removed entirely from Swift:

for var i = 1; i <= 10; i += 1 {
    print("\(i) green bottles")
}

These are called C-style for loops because they have long been a feature of C-like languages, and conceptually even pre-date C by quite a long way.

Although Swift is (just about!) a C-like language, it has a number of newer, smarter alternatives to the traditional for loop. The result: this construct has been deprecated in Swift 2.2 and will be removed "in a future version of Swift."

Note: the current deprecation warning does not say it's removed in Swift 3.0, although I suspect it will be.

To replace these old for loops, use one of the many alternatives. For example, the "green bottles" code above could be rewritten to loop over a range, like this:

for i in 1...10 {
    print("\(i) green bottles")
}

Remember, though, that it's a bad idea to create a range where the start is higher than the end: your code will compile, but it will crash at runtime. So, rather than writing this:

for i in 10...1 {
    print("\(i) green bottles")
}

…you should write this instead:

for i in (1...10).reverse() {
    print("\(i) green bottles")
}

Another alternative is just to use regular fast enumeration over an array of items, like this:

var array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

for number in array {
    print("\(number) green bottles")
}

Although if you want to be technically correct (also known as "the best kind of correct") you would write such a beast like this:

var array = Array(1...10)

for number in array {
    print("\(number) green bottles")
}

Mutability warnings

This is a simple change that is going to go a long way to help code readability. As you know, Swift developers prefer declaring things as constants (using let) rather than variables (using var). But what if you made something a variable by accident? Or if you thought you might need to change it, then never do?

As of Swift 2, you'll get warnings in your code whenever you declare variables that never change – Xcode literally examines the way you use the variable and knows if you never change it.

Comparing tuples

A tuple is simply a comma-separated list of values, where each value may or may not be named. For example:

let singer = ("Taylor", "Swift")
let alien = ("Justin", "Bieber")

In older versions of Swift, you couldn't compare two tuples without writing some unwieldy code like this:

func ==  (t1: (T, T), t2: (T, T)) -> Bool {
    return t1.0 == t2.0 && t1.1 == t2.1
}

It's not very user-friendly to require that kind of boilerplate code, and of course it would only work for tuples that have exactly two elements. In Swift 2.2, you no longer need to write that code because tuples can be compared directly:

let singer = ("Taylor", "Swift")
let alien = ("Justin", "Bieber")

if singer == alien {
    print("Matching tuples!")
} else {
    print("Non-matching tuples!")
}

Swift 2.2's automatic tuple comparison works with tuples with two elements just like the function we wrote, but it also works with tuples of other sizes – up to arity 6, which means a tuple that contains six elements.

(In case you were wondering: "arity" is pronounced like "arrity", but "tuple" is pronounced any number of ways: "toople", "tyoople" and "tupple" are all common.)

You can see how tuple comparison works by changing our two tuples like this:

let singer = ("Taylor", 26)
let alien = ("Justin", "Bieber")

Be prepared for a very long error message from Xcode, but the interesting part comes near the end:

note: overloads for '==' exist with these partially matching parameter lists: ......
((A, B), (A, B)), ((A, B, C), (A, B, C)), ((A, B, C, D), (A, B, C, D)), ((A, B, C, D, E), (A, B, C, D, E)), ((A, B, C, D, E, F), (A, B, C, D, E, F))

As you can see, Swift literally has functions to compare tuples all the way up to (A, B, C, D, E, F), which ought to be more than enough.

Tuple splat syntax is deprecated

Another feature that has been deprecated is one that has been part of Swift since 2010 (yes, years before it launched). It's been named "the tuple splat", and not many people were using it. It's partly for that reason – although mainly because it introduces all sorts of ambiguities when reading code – that this syntax is being deprecated.

In case you were curious – and let's face it, you probably are – here's an example of tuple splat syntax in action:

func describePerson(name: String, age: Int) {
    print("\(name) is \(age) years old")
}

let person = ("Taylor Swift", age: 26)
describePerson(person)

But remember: don't grow too fond of your new knowledge, because tuple splats are deprecated in Swift 2.2 and will be removed entirely in a later version.

More keywords can be used as argument labels

Argument labels are a core feature of Swift, and let us write code like this:

for i in 1.stride(through: 9, by: 2) {
    print(i)
}

Without the through or by labels, this code would lose its self-documenting nature: what do the 9 and 2 do in 1.stride(9, 2)? In this example, Swift also uses the argument labels to distinguish 1.stride(through: 9, by: 2) from 1.stride(to: 9, by: 2), which produces different results.

As of Swift 2.2, you can now use a variety of language keywords as these argument labels. You might wonder why this would be a good thing, but consider this code:

func printGreeting(name: String, repeat repeatCount: Int) {
    for _ in 0 ..< repeatCount {
        print(name)
    }
}

printGreeting("Taylor", repeat: 5)

That uses repeat as an argument label, which makes sense because the function will print a string a number of times. Because repeat is a keyword, this code would not work before Swift 2.2 – you would need to write repeat instead, which is unpleasant.

Note that there are still some keywords that may not be used, specifically var, let and inout.

Variable parameters have been deprecated

Another deprecation, but again with good reason: var parameters are deprecated because they offer only marginal usefulness, and are frequently confused with inout. These things are so sneaky I couldn't resist adding one to my Swift language tests, although I will probably have removed them by the time you read this!

To give you an example, here is the printGreeting() function modified to use var:

func printGreeting(var name: String, repeat repeatCount: Int) {
    name = name.uppercaseString

    for _ in 0 ..< repeatCount {
        print(name)
    }
}

printGreeting("Taylor", repeat: 5)

The differences there are in the first two lines: name is now var name, and name gets converted to uppercase so that "TAYLOR" is printed out five times.

Without the var keyword, name would have been a constant and so the uppercaseString line would have failed.

The difference between var and inout is subtle: using var lets you modify a parameter inside the function, whereas inout causes your changes to persist even after the function ends.

As of Swift 2.2, var is deprecated, and it's slated for removal in Swift 3.0. If this is something you were using, just create a variable copy of the parameter inside the method, like this:

func printGreeting(name: String, repeat repeatCount: Int) {
    let upperName = name.uppercaseString

    for _ in 0 ..< repeatCount {
        print(upperName)
    }
}

printGreeting("Taylor", repeat: 5)

Renamed debug identifiers: #line, #function, #file

Swift 2.1 and earlier used the "screaming snake case" symbols __FILE__, __LINE__, __COLUMN__, and __FUNCTION__, which automatically get replaced the compiler by the filename, line number, column number and function name where they appear.

In Swift 2.2, those old symbols have been replaced with #file, #line, #column and #function, which will be familiar to you if you've already used Swift 2.0's #available to check for iOS features. As the official Swift review says, it also introduces "a convention where # means invoke compiler substitution logic here."

Below I've modified the printGreeting() function so you can see both the old and new debug identifiers in action:

func printGreeting(name: String, repeat repeatCount: Int) {
    // old - deprecated!
    print("This is on line \(__LINE__) of \(__FUNCTION__)")

    // new - shiny!
    print("This is on line \(#line) of \(#function)")

    let upperName = name.uppercaseString

    for _ in 0 ..< repeatCount {
        print(upperName)
    }
}

printGreeting("Taylor", repeat: 5)

For the sake of completion, I should add that you can also use #dsohandle, but if you know what dynamic shared object handles are you probably already spotted this change yourself!

Stringified selectors are deprecated

One unwelcome quirk of Swift before 2.2 was that selectors could be written as strings, like this:

navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Tap!", style: .Plain, target: self, action: "buttonTaped")

If you look closely, I wrote "buttonTaped" rather than "buttonTapped", but Xcode wasn't able to notify me of my mistake if either of those methods didn't exist.

This has been resolved as of Swift 2.2: using strings for selectors has been deprecated, and you should now write #selector(buttonTapped) in that code above. If the buttonTapped() method doesn't exist, you'll get a compile error – another whole class of bugs eliminated at compile time!

Compile-time Swift version checking

Swift 2.2 adds a new build configuration option that makes it easy to combine code code written in versions of Swift into a single file. This might seem unnecessary, but spare a thought to people who write libraries in Swift: do they target Swift 2.2 and hope everyone is using it, or target Swift 2.0 and hope users can upgrade using Xcode?

Using the new build option lets you write two different flavours of Swift, and the correct one will be compiled depending on the version of the Swift compiler.

For example:

#if swift(>=2.2)
print("Running Swift 2.2 or later")
#else
print("Running Swift 2.1 or earlier")
#endif

Just like the existing #if os() build option, this adjusts what code is produced by the compiler: if you're using a Swift 2.2 compiler, the second print() line won't even be seen. This means you can use utter gibberish if you want:

#if swift(>=2.2)
print("Running Swift 2.2 or later")
#else
THIS WILL COMPILE JUST FINE IF YOU'RE
USING A SWIFT 2.2 COMPILER BECAUSE
THIS BIT IS COMPLETELY IGNORED!
#endif

New in Swift 3.0

All function parameters have labels unless you request otherwise

The way we call functions and methods already changed in Swift 2.0, but it's changing again and this time it's going to break everything. In Swift 2.x and earlier, method names did not require a label for their first parameter, so the name of the first parameter was usually built into the method name. For example:

names.indexOf("Taylor")
"Taylor".writeToFile("filename", atomically: true, encoding: NSUTF8StringEncoding)
SKAction.rotateByAngle(CGFloat(M_PI_2), duration: 10)
UIFont.preferredFontForTextStyle(UIFontTextStyleSubheadline)
override func numberOfSectionsInTableView(tableView: UITableView) -> Int
func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView?
NSTimer.scheduledTimerWithTimeInterval(0.35, target: self, selector: #selector(createEnemy), userInfo: nil, repeats: true)

Swift 3 makes all labels required unless you specify otherwise, which means the method names no longer detail their parameters. In practice, this often means the last part of the method name gets moved to be the name of the first parameter.

To show you how that looks, here is that Swift 2.2 code followed by its equivalent in Swift 3:

names.indexOf("Taylor")
names.index(of: "Taylor")

"Taylor".writeToFile("filename", atomically: true, encoding: NSUTF8StringEncoding)
"Taylor".write(toFile: "somefile", atomically: true, encoding: String.Encoding.utf8)

SKAction.rotateByAngle(CGFloat(M_PI_2), duration: 10)
SKAction.rotate(byAngle: CGFloat(M_PI_2), duration: 10)

UIFont.preferredFontForTextStyle(UIFontTextStyleSubheadline)
UIFont.preferredFont(forTextStyle: UIFontTextStyle.subheadline)

override func numberOfSectionsInTableView(tableView: UITableView) -> Int
override func numberOfSections(in tableView: UITableView) -> Int

func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView?
func viewForZooming(in scrollView: UIScrollView) -> UIView?

NSTimer.scheduledTimerWithTimeInterval(0.35, target: self, selector: #selector(createEnemy), userInfo: nil, repeats: true)
Timer.scheduledTimer(timeInterval: 0.35, target: self, selector: #selector(createEnemy), userInfo: nil, repeats: true)

In that last call, notice how NSTimer is now just called Timer. Several other basic types have also dropped the "NS" prefix, so you'll now see UserDefaults, FileManager, Data, Date, URL URLRequest, UUID, NotificationCenter, and more.

Those are methods you call, but this has a knock-on effect for many methods that get called too: when you're connecting to frameworks such as UIKit, they expect to follow the old-style "no first parameter name" rule even in Swift 3.

Here are some example signatures from Swift 2.2:

override func viewWillAppear(animated: Bool)
override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int
override func didMoveToView(view: SKView)
override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?)
func textFieldShouldReturn(textField: UITextField) -> Bool

In Swift 3, they all need an underscore before the first parameter, to signal that the caller (Objective-C code) won't be using a parameter label:

override func viewWillAppear(_ animated: Bool)
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
override func didMoveToView(_ view: SKView)
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?)
func textFieldShouldReturn(_ textField: UITextField) -> Bool

Omit needless words

When Swift went open source in December 2015, its shiny new API guideliness contained three fateful words: "omit needless words." This introduces another huge raft of breaking changes in Swift 3, because it means that method names that contain self-evident words now have those words removed.

Let's look at some simple examples first. First, Swift 2.2:

let blue = UIColor.blueColor()
let min = numbers.minElement()
attributedString.appendAttributedString(anotherString)
names.insert("Jane", atIndex: 0)
UIDevice.currentDevice()

Can you identify the needless words? When you're working with UIColor, of course blue is going to be a color, so saying blueColor() is needless. When you append one attributed string to another, do you really need to specify that it's an attributed string you're appending as opposed to an elephant? And why should it be a method – surely a color should be a property!

Here is that same code in Swift 3:

let blue = UIColor.blue
let min = numbers.min()
attributedString.append(anotherString)
names.insert("Jane", at: 0)
UIDevice.current

As you can see, this makes method names significantly shorter!

This change has particularly affected strings, which had repetition all over the place. The best way to demonstrate this is to show before and after code side-by-side, so in the code below the first line of each pair is Swift 2.2 and the second is Swift 3.0:

"  Hello  ".stringByTrimmingCharactersInSet(.whitespaceAndNewlineCharacterSet())
"  Hello  ".trimmingCharacters(in: .whitespacesAndNewlines)

"Taylor".containsString("ayl")
"Taylor".contains("ayl")

"1,2,3,4,5".componentsSeparatedByString(",")
"1,2,3,4,5".components(separatedBy: ",")

myPath.stringByAppendingPathComponent("file.txt")
myPath.appendingPathComponent("file.txt")

"Hello, world".stringByReplacingOccurrencesOfString("Hello", withString: "Goodbye")
"Hello, world".replacingOccurrences(of: "Hello", with: "Goodbye")

"Hello, world".substringFromIndex(7)
"Hello, world".substring(from: 7)

"Hello, world".capitalizedString
"Hello, world".capitalized

Warning: capitalized is still a property, but lowercaseString and uppercaseString have been transmogrified into the methods lowercased() and uppercased().

I've chosen the examples so far because the jump to Swift 3 isn't vast, but there are quite a few changes that were significant enough to make my brain hit a speedbump – usually when the resulting method is so short that it wasn't immediately obvious what it was.

For example, look at this code:

dismiss(animated: true, completion: nil)

When I first saw that, I blanked: "dismiss what?" That's partly a result of the Stockholm syndrome that's inevitable having programmed for iOS for so long, but once you learn to reverse the parameter label change and re-add the needless words, you can see it's equivalent to this code in Swift 2.2:

dismissViewControllerAnimated(true, completion: nil)

In fact, the completion: nil part is optional now, so you could even write this:

dismiss(animated: true)

A similar change happened to prepareForSegue(), which now looks like this:

override func prepare(for segue: UIStoryboardSegue, sender: AnyObject?)

UpperCamelCase has been replaced with lowerCamelCase for enums and properties

Although syntactically irrelevant, the capital letters we use to name classes and structs, properties, enums, and more have always followed a convention fairly closely: classes, structs, and enums use UpperCamelCase (MyStruct, WeatherType.Cloudy), properties and parameter names use lowerCamelCase (emailAddress, requestString).

I say "fairly closely" because there are some exceptions that are going to stop being exceptions in Swift 3: properties and parameters that started with initials in Swift 2.2 will now used lowerCamelCase in Swift 3.

Sometimes this isn't too strange: Swift 2.2 created NSURLRequest objects using NSURLRequest(URL: someURL) – note the capital "URL". Swift 3 rewrites that to URLRequest(url: someURL), and also means you'll use things like webView.request?.url?.absoluteString for reading the URL of a web view.

Where it's a bit more jarring is when only part of the property name is in caps, e.g. CGColor or CIColor. Yes, you've guessed it: they become cgColor and ciColor in Swift 3, so you'll be writing code like this:

let red = UIColor.red.cgColor

This change does help drive consistency: all properties and parameters should start with a lowercase letter, no exceptions.

At the same time enum cases are also changing, moving from UpperCamelCase to lowerCamelCase. This makes sense: an enum is a data type (like a struct), but enum values are closer to properties. However, it does mean that wherever you've used an Apple enum, it will now be lowercase. So:

UIInterfaceOrientationMask.Portrait // old
UIInterfaceOrientationMask.portrait // new

NSTextAlignment.Left // old
NSTextAlignment.left // new

SKBlendMode.Replace // old
SKBlendMode.replace // new

You get the idea. However, this tiny change brings something much bigger because Swift's optionals are actually just an enum under the hood, like this:

enum Optional {
    case None
    case Some(Wrapped)
}

This means if you use .Some to work with optionals, you'll need to switch to .some instead. Of course, you could always take this opportunity to ditch .some entirely – these two pieces of code are identical:

for case let .some(datum) in data {
    print(datum)
}

for case let datum? in data {
    print(datum)
}

Swifty importing of C functions

Swift 3 introduces attributes for C functions that allow library authors to specify new and beautiful ways their code should be imported into Swift. For example, all those functions that start with "CGContext" now get mapped to properties methods on a CGContext object, which makes for much more idiomatic Swift. Yes, this means the hideous wart that is CGContextSetFillColorWithColor() has finally been excised.

To demonstrate this, here's an example in Swift 2.2:

let ctx = UIGraphicsGetCurrentContext()

let rectangle = CGRect(x: 0, y: 0, width: 512, height: 512)
CGContextSetFillColorWithColor(ctx, UIColor.redColor().CGColor)
CGContextSetStrokeColorWithColor(ctx, UIColor.blackColor().CGColor)
CGContextSetLineWidth(ctx, 10)
CGContextAddRect(ctx, rectangle)
CGContextDrawPath(ctx, .FillStroke)

UIGraphicsEndImageContext()

In Swift 3 the CGContext can be treated as an object that you can call methods on rather than repeating CGContext again and again. So, we can rewrite that code like this:

if let ctx = UIGraphicsGetCurrentContext() {
    let rectangle = CGRect(x: 0, y: 0, width: 512, height: 512)
    ctx.setFillColor(UIColor.red.cgColor)
    ctx.setStrokeColor(UIColor.black.cgColor)
    ctx.setLineWidth(10)
    ctx.addRect(rectangle)
    ctx.drawPath(using: .fillStroke)

    UIGraphicsEndImageContext()
}

Note: in both Swift 2.2 and Swift 3.0 UIGraphicsGetCurrentContext() returns an optional CGContext, but because Swift 3 uses method calls we need to safely unwrap before it's used.

This mapping of C functions exists elsewhere, for example you can now read the numberOfPages property of a CGPDFDocument, and CGAffineTransform has been souped up quite dramatically. Here are some examples showing old and new:

CGAffineTransformIdentity
CGAffineTransform.identity

CGAffineTransformMakeScale(2, 2)
CGAffineTransform(scaleX: 2, y: 2)

CGAffineTransformMakeTranslation(128, 128)
CGAffineTransform(translationX: 128, y: 128)

CGAffineTransformMakeRotation(CGFloat(M_PI))
CGAffineTransform(rotationAngle: CGFloat(M_PI))

Verbs and nouns

This is the part where some people will start to drift off in confusion, which is a shame because it's important.

Here's are some quotes from the Swift API guidelines:

  • "When the operation is naturally described by a verb, use the verb’s imperative for the mutating method and apply the “ed” or “ing” suffix to name its nonmutating counterpart"
  • "Prefer to name the nonmutating variant using the verb’s past participle"
  • "When adding “ed” is not grammatical because the verb has a direct object, name the nonmutating variant using the verb’s present participle"
  • "When the operation is naturally described by a noun, use the noun for the nonmutating method and apply the “form” prefix to name its mutating counterpart"

Got that? It's no surprise that Swift's rules are expressed using lingustic terminology – it is after all a language! – but this at least gives me a chance to feel smug that I did a second degree in English. What it means is that many methods are changing names in subtle and sometimes confusing ways.

Let's start with a couple of simple examples:

myArray.enumerate()
myArray.enumerated()

myArray.reverse()
myArray.reversed()

Each time Swift 3 modifies the method by adding a "d" to the end: this is a value that's being returned.

These rules are mostly innocent enough, but it causes confusion when it comes to array sorting. Swift 2.2 used sort() to return a sorted array, and sortInPlace() to sort an array in place. In Swift 3.0, sort() is renamed to sorted() (following the examples above), and sortInPlace() is renamed to sort().

TL;DR: This means you need to be careful because in Swift 2.2 sort() returned a sorted array, but in Swift 3.0 sort() sorts the array in place.

New in Swift 3.1

Concrete constrained extensions

Swift lets us extend types using constraints, which is a powerful and expressive way to add functionality. To demonstrate this, let's look at a worked example in Swift 3.0 that modifies collections to do something trivial:

extension Collection where Iterator.Element: Comparable {
    func lessThanFirst() -> [Iterator.Element] {
        guard let first = self.first else { return [] }
        return self.filter { $0 < first }
    }
}

let items = [5, 6, 10, 4, 110, 3].lessThanFirst()
print(items)

That adds a new method called lessThanFirst(), which returns all items in a collection that are less than the first item. So, using it with the array [5, 6, 10, 4, 110, 3] will return [4, 3].

That code extends a protocol (Collection) only where it matches a constraint: elements in the collection must conform to another protocol, Comparable. This alone is powerful stuff, but let's take it back a step: what if we wanted something a bit more specific? Swift 3.0 lets us extend a concrete type rather than the protocol Collection, so instead we could write this:

extension Array where Element: Comparable {
    func lessThanFirst() -> [Element] {
        guard let first = self.first else { return [] }
        return self.filter { $0 < first }
    }
}

let items = [5, 6, 10, 4, 110, 3].lessThanFirst()
print(items)

That extends a concrete type (only Array) but still using a protocol for its constraint. What if we wanted to go even more specific – extend a concrete type with a concrete constraint, for example only arrays that contains integers? Well, it turns out that isn't possible in Swift 3.0, which usually strikes people as odd: if Swift 3.0 can handle extending protocols with another protocol as a constraint, then surely extending a specific type with a specific constraint should be a cinch?

Fortunately, this discrepancy has been removed in Swift 3.1, which means we can now write code like this:

extension Array where Element == Int {
    func lessThanFirst() -> [Int] {
        guard let first = self.first else { return [] }
        return self.filter { $0 < first }
    }
}

let items = [5, 6, 10, 4, 110, 3].lessThanFirst()
print(items)

That extends a concrete type (only Array) and uses a concrete constraint (only where the elements are Int).

Now, obviously we're using a trivial example here – in your own code this is going to be significantly more useful when you want to extend arrays containing your own custom structs.

Generics with nested types

Swift 3.0's support for nested types is useful to help you organize your data and increase encapsulation, but Swift 3.1 takes them to the next level by adding support for generics. Let's look at a simple example again, just to start with:

struct Message {
    struct Attachment {
        var contents: String
    }

    var title: String
    var attachment: Attachment
}

That creates a Message struct that has an Attachment struct inside it – a nested type. I've added two String properties, because messages will have some text and attachments will hold some text.

Now, what if we wanted either Message or Attachment to have different kinds of data – perhaps Int or Data? Well, that requires generics, so you might have found yourself writing something like this:

struct Message<T> {
    struct Attachment {
        var contents: String
    }

    var title: T
    var attachment: Attachment
}

That tells Swift we want Message to work across several data types, and whatever data type gets used to create the struct should also be used for the title property. Or at least that's what it would tell Swift, if such code were actually legal – Swift 3.0 does not allow you to mix nested type with generics. Fortunately, this is exactly what Swift 3.1 allows, because nested types can now appear inside generic types.

Not content to stop there, Swift 3.1 takes this a step further: nested types can also be generic, either using their own generic type or by inheriting the generic type of their parent. For example:

struct Message<T> {
    struct Attachment<T> {
        var contents: T
    }

    var title: T
    var attachment: Attachment<T>
}

With that code, the Message struct will have a specific type assigned to it, and the Attachment struct will always have the same type – you can't use String for one and Int for the other. So, this code will work fine:

let msg = Message(title: "Hello", attachment: Message.Attachment(contents: "World"))

Helpfully, if your goal is to make the nested type and its container use the same generic type, you don't even need to declare the nested type as generic – Swift makes the outer type available to the nested type, so in fact you can just write this:

struct Message<T> {
    struct Attachment {
        var contents: T
    }

    var title: T
    var attachment: Attachment
}

Generics are great and so are nested types, so I'm really pleased to see Swift 3.1 bring them together at last.

Sequences get prefix(while:) and drop(while:) methods

Two useful new methods have been added to the Sequence protocol: prefix(while:) and drop(while:). The former returns the longest subsequence that satisfies a predicate, which is a fancy way of saying that you give it a closure to run on every item, and it will go through all the elements in the sequence and return those that match the closure – but will stop as soon as it finds a non-matching element.

Let's take a look at a code example:

let names = ["Michael Jackson", "Michael Jordan", "Michael Caine", "Taylor Swift", "Adele Adkins", "Michael Douglas"]
let prefixed = names.prefix { $0.hasPrefix("Michael") }
print(prefixed)

That uses the hasPrefix() method to return the subsequence ["Michael Jackson", "Michael Jordan", "Michael Caine" – the first three elements in the sequence. It won't include "Michael Douglas", because that comes after the first non-Michael. If you wanted all the Michaels regardless of their position, you should use filter() instead.

The second new method, drop(while:) is effectively the opposite: it finds the longest subsequence that satisfies your predicate, then returns everything after it. For example:

let names = ["Michael Jackson", "Michael Jordan", "Michael Caine", "Taylor Swift", "Adele Adkins", "Michael Douglas"]
let dropped = names.drop { $0.hasPrefix("Michael") }
print(dropped)

That will return the subsequence ["Taylor Swift", "Adele Adkins", "Michael Douglas"] – everything after the initial Michaels.

New in Swift 4.0

Swifty encoding and decoding

We know value types are great, but we also know they interact terribly with Objective-C APIs such as NSCoding – you either need to write a shim layer or give in and use classes, both of which are unpleasant. Worse, even if you give in and switch to classes, you still need to write your encoding and decoding methods by hand, which is painful and error-prone.

Swift 4 introduces a new Codable protocol that lets you serialize and deserialize custom data types without writing any special code – and without having to worry about losing your value types. Even better, you can choose how you want the data to be serialized: you can use classic property list format or even JSON.

Let's take a look at how beautiful this is. First, here's a custom data type and some instances of it:

struct Language: Codable {
    var name: String
    var version: Int
}

let swift = Language(name: "Swift", version: 4)
let php = Language(name: "PHP", version: 7)
let perl = Language(name: "Perl", version: 6)

You can see I've marked the Language struct as conforming to the Codable protocol. With that one tiny addition, we can convert it to a Data representation of JSON like this:

let encoder = JSONEncoder()
if let encoded = try? encoder.encode(swift) {
    // save `encoded` somewhere
}

Swift will automatically encode all properties inside your data type – you don't need to do anything.

Now, if you're like me and have a long history of using NSCoding, you're probably somewhat doubtful: is that really all it takes, and how can we be sure it's working? Well, let's add some more code to try converting the Data object into a string so we can print it out, then decode it back into a new Language instance that we can read from:

if let encoded = try? encoder.encode(swift) {
    if let json = String(data: encoded, encoding: .utf8) {
        print(json)
    }

    let decoder = JSONDecoder()
    if let decoded = try? decoder.decode(Language.self, from: encoded) {
        print(decoded.name)
    }
}

Notice how decoding doesn't require a typecast – you provide the data type name as its first parameter, so Swift infers the return type from there.

Both JSONEncoder and its property list counterpart PropertyListEncoder have lots of options for customizing how they work: do you want compact JSON or pretty-printed JSON? Do you want to use ISO8601 dates or Unix epoch dates? Do you want to use binary property lists or XML? For more information on these and other options, see the Swift Evolution proposal for this new feature.

Multi-line string literals

Writing multi-line strings in Swift has always meant adding \n inside your strings to add line breaks wherever you want them. This doesn't look good in code, but at least it displays correctly for users. Fortunately, Swift 4 introduces new multi-line string literal syntax that lets you add line breaks freely and use quote marks without escaping, while still benefiting from functionality like string interpolation.

To start a string literal, you need to write three double quotation marks: """ then press return. You can then go ahead and write a string as long as you want, including variables and line breaks, before ending your string by pressing return then writing three more double quotation marks.

String literals have two important rules: when you open a string using """ the content of your string must begin on a new line, and when you end a multi-line string using """ that must also begin on a new line.

Here it is in action:

let longString = """
When you write a string that spans multiple
lines make sure you start its content on a
line all of its own, and end it with three
quotes also on a line of their own.
Multi-line strings also let you write "quote marks"
freely inside your strings, which is great!
"""

That creates a new string with several line breaks right there in the definition – much easier to read and write.

For more information see the Swift Evolution proposal for this new feature.

Improved keypaths for key-value coding

One of the most loved features of Objective-C is its ability to reference a property dynamically rather than directly – that is, to be able to say "given object X, here is the property I'd like to read" without actually reading it. These references, called keypaths, are distinct from direct property accesses because they don't actually read or write the value, they just stash it away for use later on.

If you've never used keypaths before, let me show you an analogy of how they work using regular Swift methods. We're going to define a struct called Starship and a struct called Crew, then create one instance of each:

// an example struct
struct Crew {
    var name: String
    var rank: String
}

// another example struct, this time with a method
struct Starship {
    var name: String
    var maxWarp: Double
    var captain: Crew

    func goToMaximumWarp() {
        print("\(name) is now travelling at warp \(maxWarp)")
    }
}

// create instances of those two structs
let janeway = Crew(name: "Kathryn Janeway", rank: "Captain")
let voyager = Starship(name: "Voyager", maxWarp: 9.975, captain: janeway)

// grab a reference to the `goToMaximumWarp()` method
let enterWarp = voyager.goToMaximumWarp

// call that reference
enterWarp()

Because functions are first-class types in Swift, the last two lines are able to create a reference to the goToMaximumWarp() method called enterWarp, then call that later on whenever we want to. The problem is, you can't do the same thing for properties – you can't say "create a reference to the captain's name property that I can check when the inevitable mutiny happens," because Swift will just read the property directly and you'll just get its original value.

This is fixed with keypaths: they are uninvoked references to properties just like our enterWarp() code. If you invoke the reference now you get the current value, but if you invoke the reference later you get the latest value. You can dig through any number of properties, and Swift uses its type inference to ensure you get the correct type back.

The Swift Evolution community spent quite a while discussing the correct syntax for keypaths because it needed to be something visually different from other Swift code, and the syntax they ended up with uses backslashes: \Starship.name, \Starship.maxWarp, and \Starship.captain.name. You can assign those two to a variable then use them whenever you want, on any Starship instance. For example:

let nameKeyPath = \Starship.name
let maxWarpKeyPath = \Starship.maxWarp
let captainName = \Starship.captain.name

let starshipName = voyager[keyPath: nameKeyPath]
let starshipMaxWarp = voyager[keyPath: maxWarpKeyPath]
let starshipCaptain = voyager[keyPath: captainName]

That will make starshipName a string and starshipMaxWarp a double, because Swift is able to infer the types correctly. The third example there even goes into the property of a property, and Swift still figures it out correctly.

Future plans for this include being able to access array indexes and to create keypaths from strings at runtime – for more information see the Swift Evolution proposal for this new feature.

Improved dictionary functionality

One of the most intriguing proposals for Swift 4 was to add some new functionality to dictionaries to make them more powerful, and also to make them behave more like you would expect in certain situations.

Let's start with a simple example: filtering dictionaries in Swift 3 does not return a new dictionary. Instead, it returns an array of tuples with key/value labels. For example:

let cities = ["Shanghai": 24_256_800, "Karachi": 23_500_000, "Beijing": 21_516_000, "Seoul": 9_995_000];
let massiveCities = cities.filter { $0.value > 10_000_000 }

After that code runs you can't read massiveCities["Shanghai"] because it is no longer a dictionary. Instead, you need to use massiveCities[0].value, which isn't great.

As of Swift 4 this behaves more like you would expect: you get back a new dictionary. Obviously this will break any existing code that relies on the tuple-array return type.

Similarly, the map() method on dictionaries never quite worked the way many people hoped: you got a key-value tuple passed in, and could return a single value to be added to an array. For example:

let populations = cities.map { $0.value * 2 }

That hasn't changed in Swift 4, but there is a new method called mapValues() that is going to be much more useful because it lets you transform the values and place them back into a dictionary using the original keys.

For example, this code will round and stringify all city populations, then put them back into a new dictionary with the same keys of Shanghai, Karachi, and Seoul:

let roundedCities = cities.mapValues { "\($0 / 1_000_000) million people" }

(In case you were wondering, it's not safe to map dictionary keys because you might create duplicates by accident.)

Easily my favorite new dictionary addition is a grouping initializer, which converts a sequence into a dictionary of sequences that are grouped by whatever you want. Continuing our cities example, we could use cities.keys to get back an array of city names, then group them by their first letter, like this:

let groupedCities = Dictionary(grouping: cities.keys) { $0.characters.first! }
print(groupedCities)

That will output the following:

["B": ["Beijing"], "S": ["Shanghai", "Seoul"], "K": ["Karachi"]]

Alternatively, we could group the cities based on the length of their names like this:

let groupedCities = Dictionary(grouping: cities.keys) { $0.count }
print(groupedCities)

That will output the following:

[5: ["Seoul"], 7: ["Karachi", "Beijing"], 8: ["Shanghai"]]

Finally, it's now possible to access a dictionary key and provide a default value to use if the key is missing:

let person = ["name": "Taylor", "city": "Nashville"]
let name = person["name", default: "Anonymous"]

Now, any experienced developer will probably argue that's better written using nil coalescing, and I agree. You could write this line instead using the current version of Swift:

let name = person["name"] ?? "Anonymous"

However, that doesn't work when you're modifying the dictionary value rather than just reading it. You can't modify a dictionary value in place because accessing its key returns an optional – the key might not exist, after all. With Swift 4's default dictionary values you can write much more succinct code, such as this:

var favoriteTVShows = ["Red Dwarf", "Blackadder", "Fawlty Towers", "Red Dwarf"]
var favoriteCounts = [String: Int]()

for show in favoriteTVShows {
    favoriteCounts[show, default: 0] += 1
}

That loops over every string in favoriteTVShows, and uses a dictionary called favoriteCounts to keep track of how often each item appears. We can modify the dictionary in one line of code because we know it will always have a value: either the default value of 0, or some higher number based on previous counting.

For more information see the Swift Evolution proposal for these new features.

Strings are collections again

This is a small change, but one guaranteed to make a lot of people happy: strings are collections again. This means you can reverse them, loop over them character-by-character, map() and flatMap() them, and more. For example:

let quote = "It is a truth universally acknowledged that new Swift versions bring new features."
let reversed = quote.reversed()

for letter in quote {
    print(letter)
}

This change was introduced as part of a broad set of amendments called the String Manifesto.

One-sided ranges

Last but not least, Swift 4 introduces Python-like one-sided collection slicing, where the missing side is automatically inferred to be the start or end of the collection. This has no effect on existing code because it's a new use for the existing operator, so you don't need to worry about potential breakage.

Here's an example:

let characters = ["Dr Horrible", "Captain Hammer", "Penny", "Bad Horse", "Moist"]
let bigParts = characters[..<3]
let smallParts = characters[3...]
print(bigParts)
print(smallParts)

That code will print out ["Dr Horrible", "Captain Hammer", "Penny"] then ["Bad Horse", "Moist"].

For more information see the Swift Evolution proposal for this new feature.

New in Swift 4.1

Synthesized Equatable and Hashable

The Equatable protocol allows Swift to compare one instance of a type against another. When we say 5 == 5, Swift understands what that means because Int conforms to Equatable, which means it implements a function describing what == means for two instances of Int.

Implementing Equatable in our own value types allows them to work like Swift’s strings, arrays, numbers, and more, and it’s usually a good idea to make your structs conform to Equatable just so they fit the concept of value types better.

However, implementing Equatable can be annoying. Consider this code:

struct Person {
    var firstName: String
    var lastName: String
    var age: Int
    var city: String
}

If you have two instances of Person and want to make sure they are identical, you need to compare all four properties, like this:

struct Person: Equatable {
    var firstName: String
    var lastName: String
    var age: Int
    var city: String

    static func ==(lhs: Person, rhs: Person) -> Bool {
        return lhs.firstName == rhs.firstName && lhs.lastName == rhs.lastName && lhs.age == rhs.age && lhs.city == rhs.city
    }
}

Even reading that is tiring, never mind writing it.

Fortunately, Swift 4.1 can synthesize conformance for Equatable – it can generate an == method automatically, which will compare all properties in one value with all properties in another, just like above. So, all you have to do now is add Equatable as a protocol for your type, and Swift will do the rest.

Of course, if you want you can implement == yourself. For example, if your type has an id field that identifies it uniquely, you would write == to compare that single value rather than letting Swift do all the extra work.

Swift 4.1 also introduces synthesized support for the Hashable protocol, which means it will generate a hashValue property for conforming types automatically. Hashable was always annoying to implement because you need to return a unique (or at least mostly unique) hash for every object. It’s important, though, because it lets you use your objects as dictionary keys and store them in sets.

Previously we’d need to write code like this:

var hashValue: Int {
    return firstName.hashValue ^ lastName.hashValue &* 16777619
}

For the most part that’s no longer needed in Swift 4.1, although as with Equatable you might still want to write your own method if there’s something specific you need.

Note: You still need to opt in to these protocols by adding a conformance to your type, and using the synthesized code does require that all properties in your type conform to Equatable or Hashable respectively.

For more information, see Swift Evolution proposal SE-0185.

Key decoding strategy for Codable

In Swift 4.0 a common problem was trying to use Codable with JSON that utilized snake_case for its key names rather than the camelCase we normally use in Swift. Codable was unable to understand how the two different name types were mapped, so you had to create a custom CodingKeys enum helping it out.

This is where Swift 4.1's new keyDecodingStrategy property comes in: it’s set to .useDefaultKeys by default, which does a direct mapping of JSON names to Swift properties. However, if you change it to .convertFromSnakeCase then Codable handles the name conversion for us.

For example:

let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase

do {
    let macs = try decoder.decode([Mac].self, from: jsonData)
    print(macs)
} catch {
    print(error.localizedDescription)
}

When you want to go back the other way – to convert a Codable struct with camelCase properties back to JSON with snake_case keys, set the keyEncodingStrategy to .convertToSnakeCase like this:

let encoder = JSONEncoder()
encoder.keyEncodingStrategy = .convertToSnakeCase
let encoded = try encoder.encode(someObject)

Conditional conformances

Swift 4.1 implements SE-0143, which introduced proposed conditional conformances into the language. This allows types to conform to a protocol only when certain conditions are met.

To demonstrate conditional conformances, let's create a Purchaseable protocol that we can use to buy things:

protocol Purchaseable {
   func buy()
}

We can now define a Book struct that conforms to the protocol, and prints a message when a book is bought:

struct Book: Purchaseable {
   func buy() {
      print("You bought a book")
   }
}

So far this is easy enough, but let's take it one step further: what if the user has a basket full of books, and wants to buy them all? We could loop over all books in the array by hand, calling buy() on each one. But a better approach is to write an extension on Array to make it conform to Purchaseable, then give it a buy() method that in turn calls buy() on each of its elements.

This is where conditional conformances come in: if we tried to extend all arrays, we'd be adding functionality where it wouldn't make sense – we'd be adding buy() to arrays of strings, for example, even though those strings don't have a buy() method we can call.

Swift 4.1 lets us make arrays conform to Purchaseable only if their elements also conform to Purchaseable, like this:

extension Array: Purchaseable where Element: Purchaseable {
   func buy() {
      for item in self {
         item.buy()
      }
   }
}

As you can see, conditional conformances let us constrain the way our extensions are applied more precisely than was possible before.

Conditional conformances also make large parts of Swift code easier and safer, even if you don't do any extra work yourself. For example, this code creates two arrays of optional strings and checks whether they are equal:

var left: [String?] = ["Andrew", "Lizzie", "Sophie"]
var right: [String?] = ["Charlotte", "Paul", "John"]
left == right

That might seem trivial, but that code wouldn't even compile in Swift 4.0 – both String and [String] were equatable, but [String?] was not.

The introduction of conditional conformance in Swift 4.1 means that it’s now possible to add protocol conformance to a type as long as it satisfies a condition. In this case, if the elements of the array are equatable, that means the whole thing is equatable. So, the above code now compiles in Swift 4.1

Conditional conformance has been extended to the Codable protocol in a way that will definitely make things safer. For example:

import Foundation

struct Person {
   var name = "Taylor"
}

var people = [Person()]
var encoder = JSONEncoder()
// try encoder.encode(people)

If you uncomment the encoder.encode(people) line, Swift will refuse to build your code because you're trying to encode a struct that doesn't conform to Codable. However, that code compiled cleanly with Swift 4.0, then threw a fatal error at runtime because Person doesn’t conform to Codable.

Obviously no one wants a fatal error at runtime, because it means your app crashes. Fortunately, Swift 4.1 cleans this up using conditional conformances: Optional, Array, Dictionary, and Set now only conform to Codable if their contents also conform to Codable, so the above code will refuse to compile.

Recursive constraints on associated types

Swift 4.1 implements SE-0157, which lifts restrictions on the way we use associated types inside protocols. As a result, we can now create recursive constraints for our associated types: associated types that are constrained by the protocol they are defined in.

To demonstrate this, let's consider a simple team hierarchy in a tech company. In this company, every employee has a manager – someone more senior to them that they report to. Each manager must also be an employee of the company, because it would be weird if they weren't.

We can express this relationship in a simple Employee protocol:

protocol Employee {
   associatedtype Manager: Employee
   var manager: Manager? { get set }
}

Note: I've used an optional Manager? because ultimately one person (presumably the CEO) has no manager.

Even though that's a fairly self-evident relationship, it wasn't possible to compile that code in Swift 4.0 because we're using the Employee protocol inside itself. However, this is fixed in Swift 4.1 because of the new ability to use recursive constraints on associated types.

Thanks to this new feature, we can model a simple tech company that has three kinds of team members: junior developers, senior developers, and board members. The reporting structure is also simple: junior developers are managed by senior developers, senior developers are managed by board members, and board members may be managed by another board member – e.g. the CTO reporting to the CEO.

That looks exactly as you would imagine thanks to Swift 4.1:

class BoardMember: Employee {
   var manager: BoardMember?
}

class SeniorDeveloper: Employee {
   var manager: BoardMember?
}

class JuniorDeveloper: Employee {
   var manager: SeniorDeveloper?
}

Note: I've used classes here rather than structs because BoardMember itself contains a BoardMember property and that would result in an infinitely sized struct. If one of these has to be a class I personally would prefer to make all three classes just for consistency, but if you preferred you could leave BoardMember as a class and make both SeniorDeveloper and JuniorDeveloper into structs.

Build configuration import testing

Swift 4.1 implements SE-0075, which introduces a new canImport condition that lets us check whether a specific module can be imported when our code is compiled.

This is particularly important for cross-platform code: if you had a Swift file that implemented one behavior on macOS and another on iOS, or if you needed specific functionality for Linux. For example:

#if canImport(SpriteKit)
   // this will be true for iOS, macOS, tvOS, and watchOS
#else
   // this will be true for other platforms, such as Linux
#endif

Previously you would have had to use inclusive or exclusive tests by operating system, like this:

#if !os(Linux)
   // Matches macOS, iOS, watchOS, tvOS, and any other future platforms
#endif

#if os(macOS) || os(iOS) || os(tvOS) || os(watchOS)
   // Matches only Apple platforms, but needs to be kept up to date as new platforms are added
#endif

The new canImport condition lets us focus on the functionality we care about rather than what platform we're compiling for, thus avoiding a variety of problems.

Target environment testing

Swift 4.1 implements SE-0190, which introduces a new targetEnvironment condition that lets us differentiate between builds that are for physical devices and those that are for a simulated environment.

At this time targetEnvironment has only one value, simulator, which will be true if your build is targeting a simulated device such as the iOS Simulator. For example:

#if targetEnvironment(simulator)
   // code for the simulator here
#else
   // code for real devices here
#endif

This is useful when writing code to deal with functionality the simulator doesn't support, such as capturing photos from a camera or reading the accelerometer.

As an example, let's look at processing a photo from the camera. If we're running on a real device we'll create and configure a UIImagePickerController() to take photos using the camera, but if we're in the simulator we'll just load a sample image from our app bundle:

import UIKit

class TestViewController: UIViewController, UIImagePickerControllerDelegate {
   // a method that does some sort of image processing
   func processPhoto(_ img: UIImage) {
       // process photo here
   }

   // a method that loads a photo either using the camera or using a sample
   func takePhoto() {
      #if targetEnvironment(simulator)
         // we're building for the simulator; use the sample photo
         if let img = UIImage(named: "sample") {
            processPhoto(img)
         } else {
            fatalError("Sample image failed to load")
         }
      #else
         // we're building for a real device; take an actual photo
         let picker = UIImagePickerController()
         picker.sourceType = .camera
         vc.allowsEditing = true
         picker.delegate = self
         present(picker, animated: true)
      #endif
   }

   // this is called if the photo was taken successfully
   func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
      // hide the camera
      picker.dismiss(animated: true)

      // attempt to retrieve the photo they took
      guard let image = info[UIImagePickerControllerEditedImage] as? UIImage else {
         // that failed; bail out
         return
      }

      // we have an image, so we can process it
      processPhoto(image)
   }
}

flatMap is now (partly) compactMap()

The flatMap() method was useful for a variety of things in Swift 4.0, but one was particularly useful: the ability to transform each object in a collection, then remove any items that were nil.

Swift Evolution proposal SE-0187 suggested changing this, and as of Swift 4.1 this flatMap() variant has been renamed to compactMap() to make its meaning clearer.

For example:

let array = ["1", "2", "Fish"]
let numbers = array.compactMap { Int($0) }

That will create an Int array containing the numbers 1 and 2, because "Fish" will fail conversion to Int, return nil, and be ignored.

New in Swift 4.2

Derived collections of enum cases

SE-0194 introduces a new CaseIterable protocol that automatically generates an array property of all cases in an enum.

Prior to Swift 4.2 this either took hacks, hand-coding, or Sourcery code generation to accomplish, but now all you need to do is make your enum conform to the CaseIterable protocol. At compile time, Swift will automatically generate an allCases property that is an array of all your enum’s cases, in the order you defined them.

For example, this creates an enum of pasta shapes and asks Swift to automatically generate an allCases array for it:

enum Pasta: CaseIterable {
    case cannelloni, fusilli, linguine, tagliatelle
}

You can then go ahead and use that property as a regular array – it will be a [Pasta] given the code above, so we could print it like this:

for shape in Pasta.allCases {
    print("I like eating \(shape).")
}

This automatic synthesis of allCases will only take place for enums that do not use associated values. Adding those automatically wouldn’t make sense, however if you want you can add it yourself:

enum Car: CaseIterable {
    static var allCases: [Car] {
        return [.ford, .toyota, .jaguar, .bmw, .porsche(convertible: false), .porsche(convertible: true)]
    }

    case ford, toyota, jaguar, bmw
    case porsche(convertible: Bool)
}

At this time, Swift is unable to synthesize the allCases property if any of your enum cases are marked unavailable. So, if you need allCases then you’ll need to add it yourself, like this:

enum Direction: CaseIterable {
    static var allCases: [Direction] {
        return [.north, .south, .east, .west]
    }

    case north, south, east, west

    @available(*, unavailable)
    case all
}

Important: You need to add CaseIterable to the original declaration of your enum rather than an extension in order for the allCases array to be synthesized. This means you can’t use extensions to retroactively make existing enums conform to the protocol.

Warning and error diagnostic directives

SE-0196 introduces new compiler directives that help us mark issues in our code. These will be familiar to any developers who had used Objective-C previously, but as of Swift 4.2 we can enjoy them in Swift too.

The two new directives are #warning and #error: the former will force Xcode to issue a warning when building your code, and the latter will issue a compile error so your code won’t build at all. Both of these are useful for different reasons:

  • #warning is mainly useful as a reminder to yourself or others that some work is incomplete. Xcode templates often use #warning to mark method stubs that you should replace with your own code.
  • #error is mainly useful if you ship a library that requires other developers to provide some data. For example, an authentication key for a web API – you want users to include their own key, so using #error will force them to change that code before continuing.

Both of these work in the same way: #warning("Some message") and #error("Some message"). For example:

func encrypt(_ string: String, with password: String) -> String {
    #warning("This is terrible method of encryption")
    return password + String(string.reversed()) + password
}

struct Configuration {
    var apiKey: String {
        #error("Please enter your API key below then delete this line.")
        return "Enter your key here"
    }
}    

Both #warning and #error work alongside the existing #if compiler directive, and will only be triggered if the condition being evaluated is true. For example:

#if os(macOS)
#error("MyLibrary is not supported on macOS.")
#endif

Dynamic member look up

SE-0195 introduces a way to bring Swift closer to scripting languages such as Python, but in a type-safe way – you don’t lose any of Swift’s safety, but you do gain the ability to write the kind of code you’re more likely to see in PHP and Python.

At the core of this feature is a new attribute called @dynamicMemberLookup, which instructs Swift to call a subscript method when accessing properties. This subscript method, subscript(dynamicMember:), is required: you’ll get passed the string name of the property that was requested, and can return any value you like.

Let’s look at a trivial example so you can understand the basics. We could create a Person struct that reads its values from a dictionary like this:

@dynamicMemberLookup
struct Person {
    subscript(dynamicMember member: String) -> String {
        let properties = ["name": "Taylor Swift", "city": "Nashville"]
        return properties[member, default: ""]
    }
}

The @dynamicMemberLookup attribute requires the type to implement a subscript(dynamicMember:) method to handle the actual work of dynamic member lookup. As you can see, I’ve written one that accepts the member name as string and returns a string, and internally it just looks up the member name in a dictionary and returns its value.

That struct allows us to write code like this:

let person = Person()
print(person.name)
print(person.city)
print(person.favoriteIceCream)

That will compile cleanly and run, even though name, city, and favoriteIceCream do not exist as properties on the Person type. Instead, they are all looked up at runtime: that code will print “Taylor Swift” and “Nashville” for the first two calls to print(), then an empty string for the final one because our dictionary doesn’t store anything for favoriteIceCream.

My subscript(dynamicMember:) method must return a string, which is where Swift’s type safety comes in: even though you’re dealing with dynamic data, Swift will still ensure you get back what you expected. And if you want multiple different types, just implement different subscript(dynamicMember:) methods, like this:

@dynamicMemberLookup
struct Employee {
    subscript(dynamicMember member: String) -> String {
        let properties = ["name": "Taylor Swift", "city": "Nashville"]
        return properties[member, default: ""]
    }

    subscript(dynamicMember member: String) -> Int {
        let properties = ["age": 26, "height": 178]
        return properties[member, default: 0]
    }
}

Now that any property can be accessed in more than one way, Swift requires you to be clear which one should be run. That might be implicit, for example if you send the return value into a function that accepts only strings, or it might be explicit, like this:

let employee = Employee()
let age: Int = employee.age

Either way, Swift must know for sure which subscript will be called.

You can even overload subscript to return closures:

@dynamicMemberLookup
struct User {
    subscript(dynamicMember member: String) -> (_ input: String) -> Void {
        return {
            print("Hello! I live at the address \($0).")
        }
    }
}

let user = User()
user.printAddress("555 Taylor Swift Avenue")

When that’s run, user.printAddress returns a closure that prints out a string, and the ("555 Taylor Swift Avenue") part immediately calls it with that input.

If you use dynamic member subscripting in a type that has also some regular properties and methods, those properties and methods will always be used in place of the dynamic member. For example, we could define a Singer struct with a built-in name property alongside a dynamic member subscript:

struct Singer {
    public var name = "Justin Bieber"

    subscript(dynamicMember member: String) -> String {
        return "Taylor Swift"
    }
}

let singer = Singer()
print(singer.name)

That code will print “Justin Bieber”, because the name property will be used rather than the dynamic member subscript.

@dynamicMemberLookup plays a full part in Swift’s type system, which means you can assign them to protocols, structs, enums, and classes – even classes that are marked @objc.

In practice, this means two things. First, you can create a class using @dynamicMemberLookup, and any classes that inherit from it are also automatically @dynamicMemberLookup. So, this will print “I’m a sandwich” because HotDog inherits from Sandwich:

@dynamicMemberLookup
class Sandwich {
    subscript(dynamicMember member: String) -> String {
        return "I'm a sandwich!"
    }
}

class HotDog: Sandwich { }

let chiliDog = HotDog()
print(chiliDog.description)

Second, you can retroactively make other types use @dynamicMemberLookup by defining it on a protocol, adding a default implementation of subscript(dynamicMember:) using a protocol extension, then making other types conform to your protocol however you want.

For example, this creates a new Subscripting protocol, provides a default subscript(dynamicMember:) implementation that returns a message, then extends Swift’s String to use that protocol:

@dynamicMemberLookup
protocol Subscripting { }

extension Subscripting {
    subscript(dynamicMember member: String) -> String {
        return "This is coming from the subscript"
    }
}

extension String: Subscripting { }
let str = "Hello, Swift"
print(str.username)

Enhanced conditional conformances

Conditional conformances were introduced in Swift 4.1, allowing types to conform to a protocol only when certain conditions are met.

For example, if we had a Purchaseable protocol:

protocol Purchaseable {
    func buy()
}

And a simple type that conforms to that protocol:

struct Book: Purchaseable {
    func buy() {
        print("You bought a book")
    }
}

Then we could make Array conform to Purchaseable if all the elements inside the array were also Purchasable:

extension Array: Purchaseable where Element: Purchaseable {
    func buy() {
        for item in self {
            item.buy()
        }
    }
}

This worked great at compile time, but there was a problem: if you needed to query a conditional conformance at runtime, your code would crash because it wasn’t supported in Swift 4.1

In Swift 4.2 that’s now fixed, so if you receive data of one type and want to check if it can be converted to a conditionally conformed protocol, it works great.

For example:

let items: Any = [Book(), Book(), Book()]

if let books = items as? Purchaseable {
    books.buy()
}

In addition, support for automatic synthesis of Hashable conformance has improved greatly in Swift 4.2. Several built-in types from the Swift standard library – including optionals, arrays, dictionaries, and ranges – now automatically conform to the Hashable protocol when their elements conform to Hashable.

For example:

struct User: Hashable {
    var name: String
    var pets: [String]
}

Swift 4.2 can automatically synthesize Hashable conformance for that struct, but Swift 4.1 could not.

Random number generation and shuffling

SE-0202 introduces a new random API that’s native to Swift. This means you can for the most part stop using arc4random_uniform() and GameplayKit to get randomness, and instead rely on a cryptographically secure randomizer that’s baked right into the core of the language.

You can generate random numbers by calling the random() method on whatever numeric type you want, providing the range you want to work with. For example, this generates a random number in the range 1 through 4, inclusive on both sides:

let randomInt = Int.random(in: 1..<5)

Similar methods exist for Float, Double, and CGFloat:

let randomFloat = Float.random(in: 1..<10)
let randomDouble = Double.random(in: 1...100)
let randomCGFloat = CGFloat.random(in: 1...1000)

There’s also one for booleans, generating either true or false randomly:

let randomBool = Bool.random()

Checking a random boolean is effectively the same as checking Int.random(in: 0...1) == 1, but it expresses your intent more clearly.

SE-0202 also includes support for shuffling arrays using new shuffle() and shuffled() methods depending on whether you want in-place shuffling or not. For example:

var albums = ["Red", "1989", "Reputation"]

// shuffle in place
albums.shuffle()

// get a shuffled array back
let shuffled = albums.shuffled()

It also adds a new randomElement() method to arrays, which returns one random element from the array if it isn’t empty, or nil otherwise:

if let random = albums.randomElement() {
    print("The random album is \(random).")
}

Simpler, more secure hashing

Swift 4.2 implements SE-0206, which simplifies the way we make custom types conform to the Hashable protocol.

From Swift 4.1 onwards conformance to Hashable can be synthesized by the compiler. However, if you want your own hashing implementation – for example, if your type has many properties but you know that one of them was enough to identify it uniquely – you still need to write your own code using whatever algorithm you thought was best.

Swift 4.2 introduces a new Hasher struct that provides a randomly seeded, universal hash function to make this process easier:

struct iPad: Hashable {
    var serialNumber: String
    var capacity: Int

    func hash(into hasher: inout Hasher) {
        hasher.combine(serialNumber)
    }
}

You can add more properties to your hash by calling combine() repeatedly, and the order in which you add properties affects the finished hash value.

You can also use Hasher as a standalone hash generator: just provide it with whatever values you want to hash, then call finalize() to generate the final value. For example:

let first = iPad(serialNumber: "12345", capacity: 256)
let second = iPad(serialNumber: "54321", capacity: 512)

var hasher = Hasher()
hasher.combine(first)
hasher.combine(second)
let hash = hasher.finalize()

Hasher uses a random seed every time it hashes an object, which means the hash value for any object is effectively guaranteed to be different between runs of your app.

This in turn means that elements you add to a set or a dictionary are highly likely to have a different order each time you run your app.

Checking sequence elements match a condition

SE-0207 provides a new allSatisfy() method that checks whether all items in a sequence pass a condition.

For example, if we had an array of exam results like this:

let scores = [85, 88, 95, 92]

We could decide whether a student passed their course by checking whether all their exam results were 85 or higher:

let passed = scores.allSatisfy { $0 >= 85 }

In-place collection element removal

SE-0197 introduces a new removeAll(where:) method that performs a high-performance, in-place filter for collections. You give it a closure condition to run, and it will strip out all objects that match the condition.

For example, if you have a collection of names and want to remove people called “Terry”, you’d use this:

var pythons = ["John", "Michael", "Graham", "Terry", "Eric", "Terry"]
pythons.removeAll { $0.hasPrefix("Terry") }
print(pythons)

Now, you might very well think that you could accomplish that by using filter() like this:

pythons = pythons.filter { !$0.hasPrefix("Terry") }

However, that doesn’t use memory very efficiently, it specifies what you don’t want rather than what you want, and more advanced in-place solutions come with a range of complexities that are off-putting to novices. Ben Cohen, the author of SE-0197, gave a talk at dotSwift 2018 where he discussed the implementation of this proposal in more detail – if you’re keen to learn why it’s so efficient, you should start there!

Boolean toggling

SE-0199 introduces a new toggle() method to booleans that flip them between true and false..

The entire code to implement proposal is only a handful of lines of Swift:

extension Bool {
   mutating func toggle() {
      self = !self
   }
}

However, the end result makes for much more natural Swift code:

var loggedIn = false
loggedIn.toggle()

As noted in the proposal, this is particularly useful in more complex data structures: myVar.prop1.prop2.enabled.toggle() avoids the potential typing errors that could be caused using manual negation.

The proposal makes Swift easier and safer to write, and is purely additive, so I think most folks will switch to using it quickly enough.

No results – perhaps you should broaden your filter.

Credits

What's New In Swift was written by Paul Hudson. If you have questions or comments you can tweet me @twostraws or email paul@hackingwithswift.com.

A lot of the content for this site was drawn from previous articles I've written:

I have also made some interactive playgrounds that you might want to try: What's new in Swift 4.1? and What's new in Swift 4.2?

If you're just learning Swift, Hacking with Swift has many free Swift tutorials – check them out!