What's New in Swift 4.2
What's New in Swift 4.2
2
Team: iOS
Founder: Tien Le P.
Partner: Tung Nguyen C.T
Speaker: Bien Le Q.
Contents
1. ABI stability 10. Hashable Improvements
2. Generating Random Numbers 11. Removing Elements From
3. Random in Array Collections
4. Shuffle in Array 12. Toggling Boolean States
5. Dynamic Member Lookup 13. New Pointer Functions
6. Enumeration Cases Collections 14. Memory Layout Updates
7. New Sequence Methods 15. Inline Functions in Modules
8. Testing Sequence Elements 16. Miscellaneous Bits and Pieces
9. Conditional Conformance Updates 17. Removing Implicitly Unwrapped
Optionals
References
● https://www.raywenderlich.com/5357-what-s-new-in-swift-4-2
● https://www.hackingwithswift.com/articles/77/whats-new-in-swift-4-2
3
ABI stability
● One easy way to understand "ABI" is to compare it to "API"
● Think of it as the compiled version of an API (or as an API on the machine-
language level)
● The ABI defines the structures and methods that your compiled application will
use to access the external library (just like the API did), only on a lower level.
● If a program is built to use a particular library and that library is later updated,
you don't want to have to re-compile that application (and from the end-user's
standpoint, you may not have the source).
● Link: https://stackoverflow.com/questions/2171177/what-is-an-application-binary-
interface-abi
4
Generating Random Numbers
Swift 4.1 imports C APIs to generate random numbers, as in the snippet below:
5
Generating Radom Numbers
In Swift 4.2: // 1
let digit = Int.random(in: 0..<10)
// 2
if let anotherDigit = (0..<10).randomElement()
{
print(anotherDigit)
} else {
print("Empty range.")
}
// 3
let double = Double.random(in: 0..<1)
let float = Float.random(in: 0..<1)
let cgFloat = CGFloat.random(in: 0..<1)
let bool = Bool.random()
6
Random in Array
Swift 4.1 also used C functions for generating random values from arrays:
7
Random in Array
Swift 4.2 takes a more straightforward approach:
8
Shuffle in Array
Swift 4.1 didn’t contain any collection shuffling algorithms, so you had to use a
roundabout way to achieve the intended result:
// 1
let shuffledPlaylist = playlist.sorted{ _, _ in arc4random_uniform(2) == 0 }
// 2
var names = ["Cosmin", "Oana", "Sclip", "Nori"]
names.sort{ _, _ in arc4random_uniform(2) == 0 }
9
Shuffle in Array
Swift 4.2 provides more efficient, and arguably more elegant, shuffling algorithms:
//1
let shuffledPlaylist = playlist.shuffled()
//2
names.shuffle()
10
Dynamic Member Lookup
class Person {
let name: String
let age: Int
private let details: [String: String]
init(name: String, age: Int,
details:[String: String]) {
self.name = name
let details = ["title": "Author",
self.age = age "instrument": "Guitar"]
self.details = details let me = Person(name: "Cosmin",
} age: 32,
details: details)
subscript(key: String) -> String {
switch key {
me["info"] // "Cosmin is 32 years old."
case "info": me["title"] // "Author"
return "\(name) is \(age) years old.”
default:
return details[key] ?? ""
}
}
} ● The drawing (user) coordinate system is used when you issue drawing commands.
● The view coordinate system (base space) is a fixed coordinate system relative to the view.
● The (physical) device coordinate system represents pixels on the physical screen.
11
Dynamic Member Lookup
// 1 // 2
@dynamicMemberLookup subscript(dynamicMember key: String)
class Person { -> String {
let name: String switch key {
let age: Int case "info":
private let details: [String: String] return "\(name) is \(age)
years old."
init(name: String, age: Int, default:
details: [String: String]) { return details[key] ?? ""
self.name = name }
self.age = age }
self.details = details }
}
// 3
me.info // "Cosmin is 32 years old."
● The drawing (user) coordinate system is used when you issue drawing commands.
me.title // "Author"
● The view coordinate system (base space) is a fixed coordinate system relative to the view.
● The (physical) device coordinate system represents pixels on the physical screen.
12
Enumeration Cases Collections
Swift 4.1 didn’t provide access to collections of enumeration cases by default.
enum SeasonType {
case equinox
case solstice
}
// 1
enum Seasons: String, CaseIterable {
case spring = "Spring", summer = "Summer", autumn = "Autumn", winter = "Winter"
}
enum SeasonType {
case equinox
case solstice
}
// 2
for (index, season) in Seasons.allCases.enumerated() {
let seasonType = index % 2 == 0 ? SeasonType.equinox : .solstice
print("\(season.rawValue) \(seasonType).")
} 14
Enumeration Cases Collections
You have the option of only adding certain cases to the enumeration cases array:
15
Enumeration Cases Collections
You should add all available cases manually to the array if the enumeration contains
unavailable ones:
16
Enumeration Cases Collections
You can also add cases with associated values to the enumeration cases array:
17
New Sequence Methods
● Swift 4.1 defined Sequence methods that determined either the first index of a certain
element, or the first element which satisfied a certain condition:
18
New Sequence Methods
● Swift 4.2 renames some of these methods for consistency:
index(where:) becomes firstIndex(where:), and index(of:) becomes firstIndex(of:) to
remain consistent with first(where:)
19
New Sequence Methods
● Swift 4.1 also didn’t define any Collection methods for finding either the last index of a
certain element or the last element which matched a given predicate. Here’s how you’d
handle this in 4.1:
// 1
let reversedAges = ages.reversed()
// 2
if let lastTeen = reversedAges.first(where: { $0.hasSuffix("teen") }),
let lastIndex = reversedAges.index(where: { $0.hasSuffix("teen") })?.base,
let lastMajorIndex = reversedAges.index(of: "eighteen")?.base {
print("Teenager number \(lastIndex) is \(lastTeen) years old.")
print("Teenager number \(lastMajorIndex) isn't a minor anymore.")
} else {
print("No teenagers around here.")
} 20
New Sequence Methods
● Swift 4.2 adds the corresponding Sequence methods which collapses the above down to:
You can simply use last(where:), lastIndex(where:) and lastIndex(of:) to find the previous
element and specific indices in ages.
21
Testing Sequence Elements
● A fairly simple routine absent from Swift 4.1 is a way to check whether all elements in a
Sequence satisfied a certain condition.
● Swift 4.2:
22
Conditional Conformance Updates
● Conditional conformance in extensions
● Conditional conformance runtime queries
● Hashable conditional conformance improvements in the standard library
23
Conditional Conformance Updates
● Conditional conformance in extensions
// 1
struct Tutorial : Equatable {
let title: String
let author: String
}
// 2
struct Screencast<Tutorial> {
let author: String
let tutorial: Tutorial
}
// 3
extension Screencast: Equatable where Tutorial: Equatable {
static func ==(lhs: Screencast, rhs: Screencast) -> Bool {
return lhs.author == rhs.author && lhs.tutorial == rhs.tutorial
}
}
24
Conditional Conformance Updates
● Conditional conformance in extensions
// 4
let swift41Tutorial = Tutorial(title: "What's New in Swift 4.1?",
author: "Cosmin Pupăză")
let swift42Tutorial = Tutorial(title: "What's New In Swift 4.2?",
author: "Cosmin Pupăză")
let swift41Screencast = Screencast(author: "Jessy Catterwaul",
tutorial: swift41Tutorial)
let swift42Screencast = Screencast(author: "Jessy Catterwaul",
tutorial: swift42Tutorial)
let sameScreencast = swift41Screencast == swift42Screencast
25
Conditional Conformance Updates
● Conditional conformance in extensions
Swift 4.2 adds a default implementation for Equatable conditional conformance to an extension:
// 1
struct Tutorial: Hashable, Codable {
let title: String
let author: String
}
struct Screencast<Tutorial> {
let author: String
let tutorial: Tutorial
} 26
Conditional Conformance Updates
● Conditional conformance in extensions
// 2
extension Screencast: Hashable where Tutorial: Hashable {}
extension Screencast: Codable where Tutorial: Codable {}
// 3
let screencastsSet: Set = [swift41Screencast, swift42Screencast]
let screencastsDictionary = [swift41Screencast: "Swift 4.1",
swift42Screencast: "Swift 4.2"]
// 1
class Instrument {
let brand: String
// 2
protocol Tuneable {
func tune()
} 28
Conditional Conformance Updates
● Conditional conformance runtime queries
Swift 4.2 implements dynamic queries of conditional conformances. You can see this in action
in the following code:
// 3
class Keyboard: Instrument, Tuneable {
func tune() {
print("\(brand) keyboard tuning.")
}
}
// 4
extension Array: Tuneable where Element: Tuneable {
func tune() {
forEach { $0.tune() }
}
} 29
Conditional Conformance Updates
● Conditional conformance runtime queries
Swift 4.2 implements dynamic queries of conditional conformances. You can see this in action
in the following code:
// 5
let instrument = Instrument()
let keyboard = Keyboard(brand: "Roland")
let instruments = [instrument, keyboard]
// 6
if let keyboards = instruments as? Tuneable
{
keyboards.tune()
} else {
print("Can't tune instrument.")
} 30
Conditional Conformance Updates
● Hashable conditional conformance improvements in the standard library
Optionals, arrays, dictionaries and ranges are Hashable in Swift 4.2 when their elements are
Hashable as well:z
31
Conditional Conformance Updates
● Hashable conditional conformance improvements in the standard library
Optionals, arrays, dictionaries and ranges are Hashable in Swift 4.2 when their elements are
Hashable as well:z
let cMajor = Chord(name: "C", description: "C major", notes: ["C", "E", "G"],
signature: ["sharp": nil, "flat": nil], frequency: 432...446)
let aMinor = Chord(name: "Am", description: "A minor", notes: ["A", "C", "E"],
signature: ["sharp": nil, "flat": nil], frequency: 440...446)
let chords: Set = [cMajor, aMinor]
let versions = [cMajor: "major", aMinor: "minor"]
32
Hashable Improvements
● Take the following example in Swift 4.1 which implements custom hash functions for a class:
static func ==(lhs: Country, rhs: Country) -> Bool { let countries: Set = [france, germany]
return lhs.name == rhs.name && lhs.capital ==
rhs.capital let countryGreetings = [france: "Bonjour”
}
germany: "Guten Tag"]
var hashValue: Int {
return name.hashValue ^ capital.hashValue &* 16777619
}
33
}
Hashable Improvements
● Swift 4.2 fixes this by defining universal hash functions:
You filter greetings to return only the short greetings. This doesn’t affect the
original array, so you have to make the assignment back to greetings.
35
In Swift 4.2, you can do this:
You don’t need to make the assignment back to greetings by using this way in
Swift 4.2
36
Toggling Boolean States
extension Bool {
mutating func toggle() {
self = !self
}
}
Swift 4.2 adds toggle() to Bool, so you don’t need to create extension like that.
37
New Compiler Directives
● Swift 4.2 defines compiler directives that signal issues in your code:
// 2
#error("Please fill in your credentials.")
// 1
let username = ""
#warning("There are shorter
let password = ""
implementations out
switch (username.filter { $0 != " " },
there.")
password.filter { $0 != " " }) {
case ("", ""):
let numbers = [1, 2, 3, 4, 5]
print("Invalid username and
var sum = 0
password.")
for number in numbers {
case ("", _):
sum += number
print("Invalid username.")
}
case (_, ""):
print(sum)
print("Invalid password.")
case (_, _):
print("Logged in succesfully.") 38
}
New Pointer Functions
withUnsafeBytes(of:_:) and withUnsafePointer(to:_:) only worked
for mutable variables in Swift 4.1:
let value = 10
var copy = value
withUnsafeBytes(of: ©) { pointer in print(pointer.count) }
withUnsafePointer(to: ©) { pointer in print(pointer.hashValue) }
40
Memory Layout Updates
● Swift 4.2 uses key paths to query the memory layout of stored properties:
// 3
// 1 if let xOffset = MemoryLayout.offset(of: \Circle.center.x),
struct Point {
let yOffset = MemoryLayout.offset(of: \Circle.center.y),
var x, y: Double
let radiusOffset = MemoryLayout.offset(of: \Circle.radius) {
}
// 2
print("\(xOffset) \(yOffset) \(radiusOffset)")
struct Circle { } else {
var center: Point print("Nil offset values.")
var radius: Double }
// 4
var circumference: Double { if let circumferenceOffset = MemoryLayout.offset(of:
return 2 * .pi * radius \Circle.circumference),
} let areaOffset = MemoryLayout.offset(of: \Circle.area) {
var area: Double {
print("\(circumferenceOffset) \(areaOffset)")
return .pi * radius * radius
} else {
}
}
print("Nil offset values.")
} 41
Inline Functions in Modules
public class CustomFactorial {
private let customDecrement: Bool
Here, we’re generating both the default factorial and a random one. Cross-module functions
are more efficient when inlined in Swift 4.2, so go back to FactorialKit.swift and replace
CustomFactorial with the next
43
Inline Functions in Modules
public class CustomFactorial {
@usableFromInline let customDecrement: Bool
Swift 4.2 lets you define minor versions as well with SwiftVersion cases
46
Removing Implicitly Unwrapped
Optionals
In Swift 4.1, you could use implicitly unwrapped optionals in nested types:
47
Removing Implicitly Unwrapped
Optionals
Swift 4.2 removes them from arrays, dictionaries and tuples:
48
Q&A
49
THANK YOU!
50