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 ResultimplementsEquatableandHashable.
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 DynamicFeaturesas@dynamicCallableto make it a dynamically callable type.
- To make DynamicFeaturesconform to@dynamicCallable, implementdynamicallyCall(withArguments:)anddynamicallyCall(withKeywordArguments:).
- Invoke featuresusing 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 IntwithDivisionError.
- 
divideBy(_:)throws.divisionByZeroifnumberis 0.
- Unwrap divisiontwice 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