Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds
Arrow up icon
GO TO TOP
Mastering iOS 14 Programming

You're reading from   Mastering iOS 14 Programming Build professional-grade iOS 14 applications with Swift 5.3 and Xcode 12.4

Arrow left icon
Product type Paperback
Published in Mar 2021
Publisher Packt
ISBN-13 9781838822842
Length 558 pages
Edition 4th Edition
Languages
Tools
Arrow right icon
Authors (3):
Arrow left icon
Mario Eguiluz Alebicto Mario Eguiluz Alebicto
Author Profile Icon Mario Eguiluz Alebicto
Mario Eguiluz Alebicto
Chris Barker Chris Barker
Author Profile Icon Chris Barker
Chris Barker
Donny Wals Donny Wals
Author Profile Icon Donny Wals
Donny Wals
Arrow right icon
View More author details
Toc

Table of Contents (22) Chapters Close

Preface 1. Chapter 1: What's New in iOS 14? 2. Chapter 2: Working with Dark Mode FREE CHAPTER 3. Chapter 3: Using Lists and Tables 4. Chapter 4: Creating a Detail Page 5. Chapter 5: Immersing Your Users with Animation 6. Chapter 6: Understanding the Swift Type System 7. Chapter 7: Flexible Code with Protocols, Generics, and Extensions 8. Chapter 8: Adding Core Data to Your App 9. Chapter 9: Fetching and Displaying Data from the Network 10. Chapter 10: Making Smarter Apps with Core ML 11. Chapter 11: Adding Media to Your App 12. Chapter 12: Improving Apps with Location Services 13. Chapter 13: Working with the Combine Framework 14. Chapter 14: Creating an App Clip for Your App 15. Chapter 15: Recognition with Vision Framework 16. Chapter 16: Creating Your First Widget 17. Chapter 17: Using Augmented Reality 18. Chapter 18: Creating a macOS app with Catalyst 19. Chapter 19: Ensuring App Quality with Tests 20. Chapter 20: Submitting Your App to the App Store 21. Other Books You May Enjoy

Introducing Swift 5.2

Introduced by Apple (on March 24, 2020), Swift 5.2 has handy features focused on improving the developer experience and providing additional language features. Some of the new language features seem to be oriented toward enhancing the functional programming style. Let's review these new features with some code examples.

Key path expressions as functions

This new feature allows developers to use key path expressions such as \Root.value wherever (Root) -> Value functions are allowed. Let's see it in action.

Let's create a Car struct with two properties, brand and isElectric:

struct Car {
    let brand: String
    let isElectric: Bool
}

Then, let's instantiate an array of Car structs with two cars, one that's electric and one that's not electric:

let aCar = Car(brand: "Ford", isElectric: false)
let anElectricCar = Car(brand: "Tesla", isElectric: true)
let cars = [aCar, anElectricCar]

Now, if we want to filter this cars array and get only the electric cars in it, we used to do it like this:

let onlyElectricCars = cars.filter { $0.isElectric }

We could also do it this way:

let onlyElectricCarsAgain = cars.filter { $0[keyPath: \Car.isElectric] }

Now, with Swift 5.2, we are able to do this more briefly:

let onlyElectricCarsNewWay = cars.filter(\.isElectric)

If you print the results, you will see that the output is the same:

print(onlyElectricCars)
print(onlyElectricCarsAgain)
print(onlyElectricCarsNewWay)

The output is as follows:

[__lldb_expr_5.Car(brand: "Tesla", isElectric: true)]
[__lldb_e xpr_5.Car(brand: "Tesla", isElectric: true)]
[__lldb_expr_5.Car(brand: "Tesla", isElectric: true)]

Note that this applies to more cases, such as map, compactMap, and wherever the (Root) -> Value function is allowed.

The SE-0249 proposal contains all the details behind this change. For additional reference and the motivation behind the proposal, you can check the original document at https://github.com/apple/swift-evolution/blob/master/proposals/0249-key-path-literal-function-expressions.md.

Callable values of user-defined nominal types

This new feature allows values that have a method whose base name is callAsFunction to be called like a function.

It is easier to explain this concept with a simple example. Let's create a struct called MyPow that helps us to calculate the power of a number, given the base number:

import Foundation
struct MyPow {
    let base: Double
    func callAsFunction(_ x: Double) -> Double {
        return pow(base, x)
    }
}

Now, we can calculate the pow of the base just by doing the following:

let base2Pow = MyPow(base: 2)
print(base2Pow.callAsFunction(3)) 

This print statement will have the following result:

8.0

Now, with Swift 5.2, we can calculate the pow of the base but using this method instead:

print(base2Pow(3))

This results in the same output:

8.0

The Swift SE-0253 proposal document contains all the details behind this change. For additional reference and the motivation behind the proposal, you can check the original document at https://github.com/apple/swift-evolution/blob/master/proposals/0253-callable.md.

Subscripts can now declare default arguments

When declaring a subscript, we are now able to assign a default value for an argument.

Let's see it in action with an example. We create a Building struct that contains an array of String representing floor names. We add a subscript to get the name of a floor with a given index. If the index doesn't exist, we want to get the default value, Unknown:

struct Building {
    var floors: [String]
    subscript(index: Int, default default: String = "Unknown") -> String {
        if index >= 0 && index < floors.count {
            return floors[index]
        } else {
            return `default`
        }
    }
}
let building = Building(floors: ["Ground Floor", "1st", "2nd", "3rd"])

We can see in the following output that when we access index 0 with building[0], we return the value Ground Floor:

print(building[0])

The console output is as follows:

Ground Floor

And in the following scenario, when we access the index 5 with building[5], we return the value Unknown:

print(building[5])

The console output is as follows:

Unknown

This code example shows how we can make use of default arguments when using subscripts and how it can be helpful to tackle edge cases.

Lazy filtering order is now reversed

When working with a lazy array and filter, there is a new change in the order of the operations applied to the filters chain. Take a look at the following code:

let numbers = [1,2,3,4,5]
    .lazy
    .filter { $0 % 2 == 0 }
    .filter { print($0); return true }
_ = numbers.count

In Swift 5.2, this code will print the following:

2
4

This is because the .filter { $0 % 2 == 0 } statement is applied before the .filter { print($0); return true } statement.

However, if we execute this code in a Swift version prior to 5.2, we will notice that the order will be the opposite. First, we will print all the numbers; then, we will filter and get only the even ones. The .filter statements will execute from bottom to top.

This behavior will change again if we remove .lazy from the code. Then, regardless of the Swift version, we will see the output as only 2 and 4. The filters will be applied from top to bottom, as expected.

Important note

This change can break your code and the logic of your app. Make sure you review for any similar scenario when updating your code to Swift 5.2 or later.

New and improved diagnostics

In Swift 5.2, error messages have improved in quality and precision. In the previous version, the compiler tried to guess the exact location of an error by breaking down expressions into smaller pieces. But this method left some errors out there.

Now the compiler, when encountering failures while trying to infer a type, records the location of those elements. These recordings allow the compiler to detect the exact error later on if needed.

Let's see an example compiled in Swift 5.1 versus Swift 5.2 and the output on each version. Look at this code which contains an error:

enum Test { case a, b }
func check(t: Test) {
  if t != .c {
    print("okay")
  }
}

In Swift 5.2, we get a clear error in the exact location where it happens, and with an accurate reason:

error: Chapter 1.5.playground:14:12: error: type 'Test' has no member 'c'
  if t != .c {
          ~^

As you can see, the compiler is telling us that we are trying to use a member of the enum that doesn't exist, c.

If we try to compile the same code in Swift 5.1, we will see a different (and incorrect) error message:

error: binary operator '!=' cannot be applied to operands of type 'Test' and '_'
  if t != .c {
     ~ ^  ~~~~~~

The improvements in the compiler errors make iOS developers' day-to-day debugging much more comfortable.

In this section, you have learned about the latest additions to the language and the improved diagnostics on Swift 5.2 with code examples. Now, let's jump into the features of Swift 5.3.

lock icon The rest of the chapter is locked
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at £13.99/month. Cancel anytime
Visually different images