What’s New in Swift 5?
Swift 5 is finally available in Xcode 10.2! This release brings ABI stability and improves the language with some long-awaited features. See what’s new! By Cosmin Pupăză.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
What’s New in Swift 5?
25 mins
- Getting Started
- Language Improvements
- Testing Integer Multiples
- Escaping Raw Strings
- Using New Character Properties
- Using New Unicode Scalar Properties
- Removing Subsequences
- Dictionary Updates
- Compacting Dictionaries
- Renaming Dictionary Literals
- Numeric Protocol Updates
- String Interpolation Updates
- Handling Future Enumeration Cases
- Adding Result to the Standard Library
- Conforming Never to Equatable and Hashable
- Dynamically Callable Types
- Swift Package Manager Updates
- Platform Deployment Settings
- Target Build Settings
- Dependency Mirroring
- Miscellaneous Bits and Pieces
- Making Codable Ranges
- Flattening Nested Optionals
- Removing Customization Points From Collections
- Identity Key Paths
- Initializing Literals Through Coercion
- Build Configuration Updates
- Using Variadic Parameters for Enumeration Cases With Associated Values
- Deprecating String Index Encoded Offsets
- New Pointer Methods
- SIMD Vector Updates
- Where to Go From Here?
Adding Result to the Standard Library
Swift 5 adds Result
to the standard library [SE-0235]:
// 1
enum ConnectionError: Error {
case noNetwork, noDatabase
}
// 2
let networkSuccess = Result<String, ConnectionError>.success("Network connected!")
let databaseSuccess = Result<String, ConnectionError>.success("Database connected!")
let networkFailure = Result<String, ConnectionError>.failure(.noNetwork)
let databaseFailure = Result<String, ConnectionError>.failure(.noDatabase)
let sameSuccess = networkSuccess == databaseSuccess
let sameFailure = networkFailure == databaseFailure
let success: Set = [networkSuccess, databaseSuccess]
let failure: Set = [networkFailure, databaseFailure]
let successDictionary = [
networkSuccess: try! networkSuccess.get(),
databaseSuccess: try! databaseSuccess.get()
]
let failureDictionary = [
networkFailure: ConnectionError.noNetwork,
databaseFailure: ConnectionError.noDatabase
]
Here’s how this code works:
- Declare the most common connection errors.
- Compare connection results, add them to sets. You use these sets as keys for dictionaries, since
Result
implementsEquatable
andHashable
.
Conforming Never to Equatable and Hashable
Swift 5 conforms Never
to Equatable
and Hashable
[SE-0215]:
let alwaysSucceeds = Result<String, Never>.success("Network connected!")
let neverFails = Result<String, Never>.success("Database connected!")
let alwaysFails = Result<Never, ConnectionError>.failure(.noNetwork)
let neverSucceeds = Result<Never, ConnectionError>.failure(.noDatabase)
let sameValue = alwaysSucceeds == neverFails
let sameError = alwaysFails == neverSucceeds
let alwaysSuccess: Set = [alwaysSucceeds, neverFails]
let alwaysFailure: Set = [alwaysFails, neverSucceeds]
let alwaysSuccessDictionary = [
alwaysSucceeds: try! alwaysSucceeds.get(),
neverFails: try! neverFails.get()
]
let alwaysFailureDictionary = [
alwaysFails: ConnectionError.noNetwork,
neverSucceeds: ConnectionError.noDatabase
]
In this code, you define connection results that always return values or errors, compare them, add them to sets and use them as dictionary keys.
Dynamically Callable Types
Swift 5 defines dynamically callable types that interoperate with scripting languages like Python or Ruby [SE-0216]:
// 1
@dynamicCallable
class DynamicFeatures {
// 2
func dynamicallyCall(withArguments params: [Int]) -> Int? {
guard !params.isEmpty else {
return nil
}
return params.reduce(0, +)
}
func dynamicallyCall(withKeywordArguments params: KeyValuePairs<String, Int>) -> Int? {
guard !params.isEmpty else {
return nil
}
return params.reduce(0) { $1.key.isEmpty ? $0 : $0 + $1.value }
}
}
// 3
let features = DynamicFeatures()
features() // nil
features(3, 4, 5) // 12
features(first: 3, 4, second: 5) // 8
The code above works as follows:
- Mark
DynamicFeatures
as@dynamicCallable
to make it a dynamically callable type. - To make
DynamicFeatures
conform to@dynamicCallable
, implementdynamicallyCall(withArguments:)
anddynamicallyCall(withKeywordArguments:)
. - Invoke
features
using normal syntax, and the compiler callsdynamicallyCall(withArguments:)
ordynamicallyCall(withKeywordArguments:)
.
Swift Package Manager Updates
Swift 5 adds a few features to the Swift Package Manager:
Platform Deployment Settings
Swift 5 allows you to define the minimum required platform deployment target version in Package.swift [SE-0236]:
let package = Package(name: “Package”, platforms: [
.macOS(.v10_14),
.iOS(.v12),
.tvOS(.v12),
.watchOS(.v5)
])
You use macOS()
, iOS()
, tvOS()
and watchOS()
in SupportedPlatform
to set the minimum required platform version for package
.
Target Build Settings
Swift 5 declares target-specific build settings in Package.swift. They customize how the package manager invokes build tools during target builds [SE-0238].
Dependency Mirroring
Swift 5 brings dependency mirroring to the Swift Package Manager [SE-0219].
swift package config set-mirror --package-url <package> --mirror-url <mirror>
Mirrors give you access to dependencies, even if the original source becomes unavailable or gets deleted.
set-mirror
updates a dependency with a mirror, which replaces all other ones.
Use unset-mirror
to remove mirrors from dependencies:
swift package config unset-mirror --package-url <package>
swift package config unset-mirror —mirror-url <mirror>
swift package config unset-mirror --all
Miscellaneous Bits and Pieces
Swift 5 adds a few other much-needed features and improvements:
Making Codable Ranges
Swift 5 adds Codable
conformance to ranges [SE-0239]:
let temperature = 0...10
let encoder = JSONEncoder()
let data = try! encoder.encode(temperature)
let decoder = JSONDecoder()
let temperatureRange = try! decoder.decode(ClosedRange<Int>.self, from: data)
You encode temperature
with JSONEncoder
and decode data
with JSONDecoder
since ranges implement Codable
by default in Swift 5.
Flattening Nested Optionals
Swift 4.2 creates nested optionals with try?
:
extension Int {
// 1
enum DivisionError: Error {
case divisionByZero
}
// 2
func divideBy(_ number: Int) throws -> Int {
guard number != 0 else {
throw DivisionError.divisionByZero
}
return self / number
}
}
// 3
let number: Int? = 10
let division = try? number?.divideBy(2)
if let division = division,
let final = division {
print(final)
}
Here’s what this code does:
- Extend
Int
withDivisionError
. -
divideBy(_:)
throws.divisionByZero
ifnumber
is 0. - Unwrap
division
twice since it’s anInt??
.
Swift 5 handles this differently [SE-0230]:
if let division = division {
print(division)
}
try?
in Swift 5 doesn’t create nested optionals, so you unwrap division
once since it’s an Int?
.
Removing Customization Points From Collections
You have access to customization points from Collection
in Swift 4.2:
extension Array {
var first: Element? {
return !isEmpty ? self[count - 1] : nil
}
var last: Element? {
return !isEmpty ? self[0] : nil
}
}
let names = ["Cosmin", "Oana", "Sclip", "Nori"]
names.first // "Nori"
names.last // "Cosmin"
In this code, first
returns the last name from names
, and last
returns the first element of the array.
Both computed properties don’t work as expected, so Swift 5 removes their customization points from collections [SE-0232].
Identity Key Paths
Swift 4.2 uses .self
to access values:
class Tutorial {
let title: String
let author: String
init(title: String, author: String) {
self.title = title
self.author = author
}
}
var tutorial = Tutorial(title: "What's New in Swift 5.0?", author: "Cosmin Pupaza")
tutorial.self = Tutorial(title: "What's New in Swift 5?", author: "Cosmin Pupăză")
In this code, you use .self
to change the tutorial’s title
and author
in one go.
Swift 5 adds identity key paths for value access [SE-0227]:
tutorial[keyPath: \.self] = Tutorial(
title: "What's New in Swift 5?",
author: "Cosmin Pupăză")
In this code, you use \.self
to update tutorial
.
Initializing Literals Through Coercion
In Swift 5, literal initializers coerce the literal to its type if the type conforms to the literal protocol [SE-0213]:
let value = UInt64(0xFFFF_FFFF_FFFF_FFFF)
In Swift 4.2, the line of code above produces an overflow error at compile time.
Build Configuration Updates
Swift 4.2 uses >=
in compilation conditions:
let favoriteNumber = 10
var evenNumber = true
#if !swift(>=5)
evenNumber = favoriteNumber % 2 == 0
#else
evenNumber = favoriteNumber.isMultiple(of: 2)
#endif
#if !compiler(>=5)
evenNumber = favoriteNumber % 2 == 0
#else
evenNumber = favoriteNumber.isMultiple(of: 2)
#endif
These conditions check if the Swift version is greater than or equal to 5 and compile those bits of code if the condition is met.
Swift 5 adds <
for cleaner conditions [SE-0224]:
#if swift(<5)
evenNumber = favoriteNumber % 2 == 0
#else
evenNumber = favoriteNumber.isMultiple(of: 2)
#endif
#if compiler(<5)
evenNumber = favoriteNumber % 2 == 0
#else
evenNumber = favoriteNumber.isMultiple(of: 2)
#endif