0% found this document useful (0 votes)
41 views50 pages

What's New in Swift 4.2

Swift 4.2 includes several new features for generating random numbers, shuffling arrays, dynamic member lookup, and working with enumeration case collections. Specifically, it allows generating random numbers without importing Foundation, provides an array shuffle method, enables dynamic member lookup with a new attribute, and adds support for accessing all enumeration cases via a default array. These changes improve the language's support for common tasks.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
41 views50 pages

What's New in Swift 4.2

Swift 4.2 includes several new features for generating random numbers, shuffling arrays, dynamic member lookup, and working with enumeration case collections. Specifically, it allows generating random numbers without importing Foundation, provides an array shuffle method, enables dynamic member lookup with a new attribute, and adds support for accessing all enumeration cases via a default array. These changes improve the language's support for common tasks.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 50

What’s New in Swift 4.

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:

let digit = Int(arc4random_uniform(10))

arc4random_uniform(_:) returned a random digit between 0 and 9. It required


you to import Foundation

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:

let playlist = ["Nothing Else Matters", "Stairway to Heaven",


"I Want to Break Free", "Yesterday"]

let index = Int(arc4random_uniform(UInt32(playlist.count)))


let song = playlist[index]

7
Random in Array
Swift 4.2 takes a more straightforward approach:

if let song = playlist.randomElement() {


print(song)
} else {
print("Empty playlist.")
}

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 Seasons: String {


case spring = "Spring", summer = "Summer", autumn = "Autumn", winter = "Winter"
}

enum SeasonType {
case equinox
case solstice
}

let seasons = [Seasons.spring, .summer, .autumn, .winter]


for (index, season) in seasons.enumerated() {
let seasonType = index % 2 == 0 ? SeasonType.equinox : .solstice
print("\(season.rawValue) \(seasonType).")
}
13
Enumeration Cases Collections
Swift 4.2 adds enumeration cases arrays to enumerations:

// 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:

enum Months: CaseIterable {


case january, february, march, april, may, june, july, august,
september, october, november, december

static var allCases: [Months] {


return [.june, .july, .august]
}
}

15
Enumeration Cases Collections
You should add all available cases manually to the array if the enumeration contains
unavailable ones:

enum Months: CaseIterable {


case january, february, march, april, may, june, july, august,
september, october, november, december

static var allCases: [Months] {


return [.june, .july, .august]
}
}

16
Enumeration Cases Collections
You can also add cases with associated values to the enumeration cases array:

enum BlogPost: CaseIterable {


case article
case tutorial(updated: Bool)

static var allCases: [BlogPost] {


return [.article, .tutorial(updated: true), .tutorial(updated: false)]
}
}

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:

let ages = ["ten", "twelve", "thirteen", "nineteen", "eighteen",


"seventeen", "fourteen", "eighteen",
"fifteen", "sixteen", "eleven"]

if let firstTeen = ages.first(where: { $0.hasSuffix("teen") }),


let firstIndex = ages.index(where: { $0.hasSuffix("teen") }),
let firstMajorIndex = ages.index(of: "eighteen") {
print("Teenager number \(firstIndex + 1) is \(firstTeen) years old.")
print("Teenager number \(firstMajorIndex + 1) isn't a minor anymore.")
} else {
print("No teenagers around here.")
}

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:)

if let firstTeen = ages.first(where: { $0.hasSuffix("teen") }),


let firstIndex = ages.firstIndex(where: { $0.hasSuffix("teen") }),
let firstMajorIndex = ages.firstIndex(of: "eighteen") {
print("Teenager number \(firstIndex + 1) is \(firstTeen) years old.")
print("Teenager number \(firstMajorIndex + 1) isn't a minor anymore.")
} else {
print("No teenagers around here.")
}

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.

if let lastTeen = ages.last(where: { $0.hasSuffix("teen") }),


let lastIndex = ages.lastIndex(where: { $0.hasSuffix("teen") }),
let lastMajorIndex = ages.lastIndex(of: "eighteen") {
print("Teenager number \(lastIndex + 1) is \(lastTeen) years old.")
print("Teenager number \(lastMajorIndex + 1) isn't a minor anymore.")
} else {
print("No teenagers around here.")
}

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.

let values = [10, 8, 12, 20]


let allEven = !values.contains { $0 % 2 == 1 }

● Swift 4.2:

let allEven = values.allSatisfy { $0 % 2 == 0 }

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:

extension Screencast: Equatable where Tutorial: Equatable {}

This feature applies to Hashable and Codable conformances in extensions as well:

// 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"]

let screencasts = [swift41Screencast, swift42Screencast]


let encoder = JSONEncoder()
do {
try encoder.encode(screencasts)
} catch {
print("\(error)")
} 27
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:

// 1
class Instrument {
let brand: String

init(brand: String = "") {


self.brand = brand
}
}

// 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

struct Chord: Hashable {


let name: String
let description: String?
let notes: [String]
let signature: [String: [String]?]
let frequency: CountableClosedRange<Int>
}

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:

class Country: Hashable {


let name: String
let capital: String
let france = Country(name: "France",
init(name: String, capital: String) {
capital: "Paris")
self.name = name
self.capital = capital let germany = Country(name: "Germany",
} capital: "Berlin")

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:

class Country: Hashable {


let name: String
let capital: String

init(name: String, capital: String) {


self.name = name
self.capital = capital
}

static func ==(lhs: Country, rhs: Country) -> Bool {


return lhs.name == rhs.name && lhs.capital == rhs.capital
}

func hash(into hasher: inout Hasher) {


hasher.combine(name)
hasher.combine(capital)
}
}
34
Removing Elements From Collections
You’ll often want to remove all occurrences of a particular element from a
Collection. Here’s a way to do it in Swift 4.1 with filter(_:):

var greetings = ["Hello", "Hi", "Goodbye", "Bye"]


greetings = greetings.filter { $0.count <= 3 }

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:

greetings.removeAll { $0.count > 3 }

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
}
}

var isOn = true


isOn.toggle()

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: &copy) { pointer in print(pointer.count) }
withUnsafePointer(to: &copy) { pointer in print(pointer.hashValue) }

You had to create a copy of value to make both functions work


39
Swift 4.2 overloads these functions for constants, so you no longer need to save
their values:

withUnsafeBytes(of: value) { pointer in print(pointer.count) }


withUnsafePointer(to: value) { 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

public init(_ customDecrement: Bool = false) {


self.customDecrement = customDecrement
}

private var randomDecrement: Int {


return arc4random_uniform(2) == 0 ? 2 : 3
}

public func factorial(_ n: Int) -> Int {


guard n > 1 else {
return 1
}
let decrement = customDecrement ? randomDecrement : 1
return n * factorial(n - decrement)
}
} 42
Inline Functions in Modules
● You’ve created a custom version of the factorial implementation. Switch back to the playground
and add this code at the bottom:

let standard = CustomFactorial()


standard.factorial(5)
let custom = CustomFactorial(true)
custom.factorial(5)

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

public init(_ customDecrement: Bool = false) {


self.customDecrement = customDecrement
}

@usableFromInline var randomDecrement: Int {


return Bool.random() ? 2 : 3
}

@inlinable public func factorial(_ n: Int) -> Int {


guard n > 1 else {
return 1
}
let decrement = customDecrement ? randomDecrement : 1
return n * factorial(n - decrement)
}
} 44
Miscellaneous Bits and Pieces
● Swift Package Manager Updates:
Defining Swift language versions for packages
Swift 4.1 defined swiftLanguageVersions in Package.swift as [Int], so you could declare only
major releases for your packages:

let package = Package(name: "Package", swiftLanguageVersions: [4])

Swift 4.2 lets you define minor versions as well with SwiftVersion cases

let package = Package(name: "Package", swiftLanguageVersions: [.v4_2])

You can also use .version(_:) to declare future releases

let package = Package(name: "Package", swiftLanguageVersions: [.version("5")])


45
Miscellaneous Bits and Pieces
● Swift Package Manager Updates:
Declaring local dependencies for packages
In Swift 4.1, you declared dependencies for your packages using repository links.
This added overhead if you had interconnected packages, so Swift 4.2 uses local
paths in this case instead

Adding system library targets to packages

System-module packages required separate repositories in Swift 4.1. This


made the package manager harder to use, so Swift 4.2 replaces them with
system library targets

46
Removing Implicitly Unwrapped
Optionals
In Swift 4.1, you could use implicitly unwrapped optionals in nested types:

let favoriteNumbers: [Int!] = [10, nil, 7, nil]


let favoriteSongs: [String: [String]!] = ["Cosmin": ["Nothing Else
Matters", "Stairway"],
"Oana": nil]
let credentials: (usermame: String!, password: String!) = ("Cosmin", nil)

47
Removing Implicitly Unwrapped
Optionals
Swift 4.2 removes them from arrays, dictionaries and tuples:

let favoriteNumbers: [Int?] = [10, nil, 7, nil]


let favoriteSongs: [String: [String]?] = ["Cosmin": ["Nothing Else
Matters", "Stairway"],
"Oana": nil]
let credentials: (usermame: String?, password: String?) = ("Cosmin", nil)

48
Q&A

49
THANK YOU!

50

You might also like