July 12, 2021
Error handling in Swift

Error handling is essential for the success of every application, ensuring end users can easily navigate through the app and use the features correctly.

In this tutorial, we’ll learn how to detect and resolve errors in a simple bookstore application built using Swift, the general-purpose programming language developed by Apple and the open source community.

Prerequisites

To begin this tutorial, ensure you have the following:

Familiarity with Swift programing
Xcode installed on your local machine

Online Swift Playground for Windows users

Setting up the project

To begin building our bookstore application, let’s create a blank Xcode playground by opening an Xcode application and selecting Empty in the Other tab.

Next, create a new playground file inside the newly created directory and name it.

There should be default code in the file; modify it to the code below and click the Play button to ensure the code is running:

import UIKit

var str = “Hello, playground”

print(str)

Running this application prints Hello, playground on the console.

With all this done, we are ready to start building.

Building an application with Swift

Since we are building a simple bookstore application, we must create two classes: one for the user purchasing a book and the other for the purchased item.

The User class contains the user’s name and available balance, while the Item class contains the name of the book, price of the book, and the quantity of the book left in the store:

class User {
var name: String
var walletBalance: Double

init(name: String, walletBalance: Double) {
self.name = name
self.walletBalance = walletBalance
}
}

class Item {
var bookName: String
var price: Double
var qtyLeft: Int

init(bookName: String, price: Double, qtyLeft: Int){
self.bookName = bookName
self.price = price
self.qtyLeft = qtyLeft
}
}

In our example, a user has a specific wallet balance to purchase a book from the store. To ensure this can be done within our app, we must create a default user and book:

let user1 = User(name: “Wisdom Ekpot”, walletBalance: 2000)
let storeItem = Item(bookName: “Oliver Twist”, price: 1000, qtyLeft: 12)

Next, let’s create a function that allows the user to purchase a book from the store:

func purchaseBookFromStore (user: User, book: Item){
user.walletBalance -= book.price
book.qtyLeft -= 1

print(“(user.name) successfully purchased (book.bookName) from the store at (book.price) naira”)
print(“Total number of books remaining = (book.qtyLeft)”)
print(“New wallet balance = (user.walletBalance)”)
}

This function takes in the User class and Item class as parameters. The function then deducts the book price from the user’s wallet balance and reduces the quantity of the Oliver Twist book available to purchase.

After reducing both quantities, the function prints out the number of books left and the user’s wallet balance. To run the program, we must call the function name and pass the User and Item classes as parameters:

purchaseBookFromStore(user: user1, book: Item)

Click the Play button to run the application. Once the program finishes compiling, the following prints on the console:

Error test cases in a Swift app

Two major issues can arise in this application that we haven’t considered:

What if the user’s wallet balance can’t afford a book in the store?
What if the quantity of books in the store is less than the amount the user wants to purchase?

Let’s test our current code with these test cases individually.

Price error

If we set the user’s wallet balance to $500 with let user1 = User(name: “Wisdom Ekpot”, walletBalance: 500), and then try to purchase $1000 of Oliver Twist book copies with let storeItem = Item(bookName: “Oliver Twist”, price: 1000, qtyLeft: 12), the following prints on the console:

The new wallet balance of the user is now -500.0, which is an error. Instead of deducting the total book price from the user’s wallet, we must print an error message when the user’s wallet balance is less than the book price.

Quantity error

Another test case that we can encounter in our shopping app is when there are fewer books in the store than books needed by a user.

If we set the quantity of the Oliver Twist book in the store to 0 with let storeItem = Item(bookName: “Oliver Twist”, price: 1000, qtyLeft: 0), and then call the purchaseBookFromStore function to buy 1 book, the console prints the following:

As we can see, the total number of books in the store is now -1. Again, printing an error message here would let the user know that the number of books in the store is less than the amount required.

Handling errors in a Swift app

To fix these error cases, let’s write a condition to check whether the user can afford this book and whether the quantity of the book available is less than the quantity required by the user. If the user cannot afford the book or there is not enough quantity of the book, we can throw an error.

Inside the purchaseBookFromStore function block, add this condition before performing any operation:

if user.walletBalance < book.price || book.qtyLeft <= 0 {
throw NSError()
}

At this point, an error throws if the condition is met, and the code below the condition won’t execute.

We must also ensure this function has the ability of throwing an error. To do this, we must modify our purchaseBookFromStore function with the following:

func purchaseBookFromStore (user: User, book: Item) throws {

if user.walletBalance < book.price || book.qtyLeft <= 0 {
throw NSError()
}
user.walletBalance -= book.price
book.qtyLeft -= 1

print(“(user.name) successfully purchased (book.bookName) from the store at (book.price) naira”)
print(“Total number of books remaining = (book.qtyLeft)”)
print(“New wallet balance = (user.walletBalance)”)
}

Notice the throws keyword before the curly brackets; this modifies how we are calling the function and indicates it can throw an error.

Next, we must wrap our purchaseBookFromStore function in a do-catch block. If the function returns an error, the catch block catches the error and prints it out on the console:

do{
try purchaseBookFromStore(user: user1, book: storeItem)
}catch {
print(“something went wrong”)
}

If we run our application again, we get the following on the console. Remember to use any of the error test cases we mentioned earlier to get the error message on the console.

Throwing a defined error

With the current state of our application, the function is not throwing the appropriate error to tell us what went wrong. To do this, we must define custom errors that we want to throw using a Swift enum, which conforms to the built-in Swift error class.

Swift enums are particularly suited for modeling a group of related error conditions because it groups related values and enables us to work with those values in a type-safe way within the code:

enum PurchaseError: Error {
case InsufficentWalletBalance
case InsufficentBookQty
}

With this enum defined, we must break the condition in our purchaseBookFromStore function into two separate conditions like the following:

if user.walletBalance < book.price{

}

if book.qtyLeft <= 0 {

}

Now, if the user has an insufficient wallet balance, our condition looks like this:

if user.walletBalance < book.price{
throw PurchaseError.InsufficentWalletBalance
}

If there are fewer books in the store compared to how many the user wants to buy, our condition looks like this:

if book.qtyLeft <= 0 {
throw PurchaseError.InsufficentBookQty
}

Finally, we can now catch the individual errors like so:

do{
try purchaseBookFromStore(user: user1, book: storeItem)
}catch PurchaseError.InsufficentWalletBalance {
print(“You don’t have sufficent funds to carry out this transaction”)
}catch PurchaseError.InsufficentBookQty{
print(“Insufficent item quantity”)
}catch{
print(“Something went wrong”)
}

The last catch block acts as a default catch block when throwing an undefined error.

Conclusion

Handling errors and displaying custom errors are essential for any successful application. By defining errors and utilizing the do-catch feature in Swift, we can understand why they occur and solve issues faster. You can get the entire source code for this project on GitHub.

The post Error handling in Swift appeared first on LogRocket Blog.

Leave a Reply

Your email address will not be published. Required fields are marked *

Send