Lets piggyback off of the previous blog post where I showed you why private(set) was needed to protect your variables. You can read that post here : Using private(set) and why it's important.
Here is the code that we're going to be referencing from that tutorial.
struct BankAccount {
var owner:String
private(set) var balance:Double
mutating func depositIntoAccount(amount: Double){
balance += amount
}
}
We're going to create a new function to withdraw money from the bank account.
struct BankAccount {
var owner:String
private(set) var balance:Double
mutating func depositIntoAccount(amount: Double){
balance += amount
}
mutating func withdraw(amount: Double){
balance -= amount
}
}
Now that we have a function to withdraw money from the bank account, let's call it. I'm running this code in playground.
struct BankAccount {
var owner:String
private(set) var balance:Double
mutating func depositIntoAccount(amount: Double){
balance += amount
}
mutating func withdraw(amount: Double){
balance -= amount
}
}
var myAccount = BankAccount(owner: "Jim", balance: 200.0)
myAccount.depositIntoAccount(amount: 20)
print(myAccount.balance)
myAccount.withdraw(amount: 201)
print(myAccount.balance)
Open up playground and run this code.
The starting balance is $200 dollar. We deposit $20 dollars and then withdraw $201. Our ending balance is $19 dollars.
We have a serious problem!
What happens if I decided to withdraw $225 dollars instead of $201? The balance would be negative.
We have to put requirements in place before we allow the balance to be changed. We're going to use swift guard for these requirements because it's cleaner then multiple if statements. It's more professional.
Using guard will make your life so much easier. I promise!
Guard may look scary but all it means is that something must be TRUE before the main thing can happen.
If it's not true then the code under it doesn't run.
Just like a bouncer at a night club. He guards your age. If your age, you enter the club and if your not you don't get pass those doors.
Let's hire a couple of bouncers and give them instructions!
The withdrawal amount has to be greater than 0.
The bank account balance has to be greater than or equal to the withdrawal amount.
guard amount > 0 else {return}
guard balance >= amount else {return}
Add these guards before you change the balance in the withdrawal function.
import SwiftUI
struct BankAccount {
var owner:String
private(set) var balance:Double
mutating func depositIntoAccount(amount: Double){
balance += amount
}
mutating func withdraw(amount: Double){
guard amount > 0 else {return}
guard balance >= amount else {return}
balance -= amount
}
}
var myAccount = BankAccount(owner: "Jim", balance: 200.0)
myAccount.depositIntoAccount(amount: 20)
print(myAccount.balance)
myAccount.withdraw(amount: 201)
print(myAccount.balance)
If both of these guard are TRUE the withdrawal will occur. Lets add a few print statements to
these guards and withdraw some money!
struct BankAccount {
var owner:String
private(set) var balance:Double
mutating func depositIntoAccount(amount: Double){
balance += amount
}
mutating func withdraw(amount: Double){
guard amount > 0 else {
print("Amount needs to be positive")
return}
guard balance >= amount else {
print("Insufficient funds")
return}
balance -= amount
print("Success! Remaining balance: \(balance)")
}
}
var myAccount = BankAccount(owner: "Jim", balance: 200.0)
myAccount.depositIntoAccount(amount: 20)
print(myAccount.balance)
myAccount.withdraw(amount: 800)
print(myAccount.balance)
Now try to withdraw $800 and see if you can! Guard doesn't allow this to happen and if you were to try and accomplish this with multiple if statements your code would be messy and who wants to fall into the category of pyramid doom.
Use guard for preconditions, when the condition must be true for the rest of the function to work.
Use IF when there are two or more valid paths and the function can continue either way it goes.
The output of trying to withdraw 800 is below
220.0
Insufficient funds
220.0
Check out my notes on error handling using enums : Stop Guessing Why Code Fails: Using Swift Enums for Detailed Error Handling. In this blog post, I will show you how to add error handling to the BankAccount using enums and do-try-catch.
Get the next useful build in your inbox.
New components, integrations, courses, and technical notes. No generic newsletter filler.
Need the implementation too?
Browse reusable components, complete flows, integrations, and training built from the same work.
2 comments
[…] to always use private(set) in your code when it’s necessary.Check out my blog post Swift Guard vs If: Why the “Bouncer” Beats the “Pyramid” to learn how to use guard to set prevent our function from creating a negative […]
[…] It’s important to use swift for error handling in your structs. I’m going to show you how to do this with enums. I’m excited because I really do like enums, I think their very powerful and you should be using them in your code. I’m going to refactor the BankAccount struct with new logic. I previously covered guard in this tutorial: Swift Guard vs If: Why the “Bouncer” Beats the “Pyramid”. […]