The Startup
Published in

The Startup

The Ultimate Guide to Swift Conditionals

Photo by Caleb Jones on Unsplash

The if-statement

var appleCount = 3
var bananaCount = 1
if appleCount > bananaCount {
print("We have more apples than bananas!")
}
if appleCount {
print("We have apples > or < 0") // This code won't work!
}

Swift always wants you to be very thoughtful.

The error says ‘Type ‘Int’ cannot be used as a boolean; test for ‘!=0’ instead

else and else if

if appleCount > bananaCount {
print("We have more apples than bananas!")
} else if appleCount == bananaCount {
print("We have the same amount of apple and bananas!")
} else {
print("We have more bananas than apples!")
}
  1. You need no braces for else-if as well.
  2. An else-statement has no condition. It will always execute when none of the above if/else-if conditions were evaluated to true.
  3. You can have only one if- and one else-condition. But you can have an unlimited amount of else-if-statements.
  4. As soon as one condition evaluated to true, the following else-if-statements will not be evaluated! The code in their blocks will not be executed! Even if that condition would have been true as well! So be careful when multiple if-/else-if-statements could be true at the same time. Make sure that you have the correct order in place!

The if-let-statement

An optional is a special type of a variable, constant or property that either has a value of its type or no value (nil).

var optionalText: String? = "Hi folks!"
optionalText = nil
var optionalText: String? = "Hi folks!"
optionalText = nil
if let text = optionalText {
print("Hooray! We have a text: \(text)")
}
var optionalText: String? = nil
optionalText = "Hi folks!"
if let text = optionalText {
print("Hooray! We have a text: \(text)")
}

The guard-statement

func danceInTheClub() {
let goodShoes = true
let
niceHair = true
let
tieToMatchTheShirt = false
guard goodShoes && niceHair && tieToMatchTheShirt else {
return
}

print("Yeah, I can dance all night!")
}
  1. The guard-statement only executes its else-block, when the criteria is not met!
  2. The guard-statement uses an else at the end. This is mandatory to form a valid guard and is what happens on exit!
  3. The code inside the guard-statement must (!!!) exit its scope. So you need one of the following: return, continue, break, or throw.
  4. The code after the guard gets only executed if all guard conditions were evaluated to true.

The guard-let-statement

func printNames() {
let firstName = "Manuel"
let lastName = "Schulze"
let middleName: String? = nil
print("My first name is: \(firstName)")
print("My last name is: \(lastName)")
guard let midName = middleName else {
return
}
print("My middle name is: \(midName)")
}

Why do I prefer guard over if?

func playAndRecordSoccer() {
let haveSoccerShoes = true
let
haveBall = true
let
haveCamera = true
if haveBall {
print("We take our ball!")
if haveSoccerShoes {
print("We take our shoes!")
if haveCamera {
print("We take our camera and record our crazy goals!")
}
}
}
}
func playAndRecordSoccerGuard() {
let haveSoccerShoes = true
let
haveBall = true
let
haveCamera = true
guard haveBall else { return }
print("We get our ball!")
guard haveSoccerShoes else { return }
print("We get our shoes!")
guard haveCamera else { return }
print("We get our camera and record our crazy goals!")
}

Provide default-values with the nil-coalescing operator ??

func loadUsername() -> String? {
// Some code could be here that either returns a string or nil
return nil
}
var usernameFromServer: String? = loadUsername()
var username = usernameFromServer ?? "stranger"
print("Hello \(username)")

The ternary-operator

  1. The condition that should be checked.
  2. The ‘happy-path’. So the value that is used when the condition is evaluated to true.
  3. The ‘unhappy-path’. The value that is used when the condition is evaluated to false.
let limit = 0.5
let outOfTolerance = 0.6
var color: UIColor = outOfTolerance <= limit ? .green : .red

The switch-statement

let favoriteFruitManuel = "Bananas"
let yourFavoriteFruit = "Watermelons"
switch yourFavoriteFruit {
case favoriteFruitManuel:
print("BANANA!")
case "Apples":
print("An apple a day, keep the doctor away!")
default:
print("You have a unique taste and like something else!")
}
  • A switch statement can have a boolean expression but usually is used to check for equality. In the example, you can see that we check if yourFavoriteFruit is equal to favoriteFruitManuel or the string "Apples”.
  • That means you can compare them to constants, variables, or properties.
  • But also check for matches with literals (42, “Hello”, true, 3.14159, etc.).
  • The case-statements have no indentation. They are usually on the same level as the switch statement. The block of code that gets executed if one case evaluates to true doesn't have braces but is indented.
  • You need to provide one case-statement for each case that could occur.
  • However, if that’s an unlimited amount of cases or you just don’t want/have to provide a case-statement for each case, you can use the default-case, which works like the else-statement in if-else. More on the default-case later.
  • Unlike many other languages, you don’t need a break at the end of the case to avoid that your program calls every single case that follows (falls through).
enum Days {
case monday, tuesday, wednesday, thursday, friday
case saturday, sunday
}
let today = Days.saturdayswitch today {
case .saturday, .sunday:
print("Hooray weekend!")
default:
print("Yeah, coding time!")
}
  1. You can see, how we separate multiple values in a case-statement with case .saturday, .sunday:. They share the code that gets executed when there is a match of today with one of them.
  2. Notice, that this is where switch-statements really shine. They are perfect in conjunction with enums. For an enum, you provide a fixed amount of cases (don’t confuse them with switch-cases) that can occur. Like days in a week.

Switch-statements: Optionals

let favoriteBook: String? = "Clean Coder"switch favoriteBook {
case let book where book == "Clean Coder":
print("A great book that teaches professionalism as a coder")
case let book where book == "Refactoring":
print("A great book that teaches you how to improve your code")
default:
print("Another favorite book or none")
}
let cleanCoder = "Clean Coder"
let refactoring = "Refactoring"
let favoriteBook: String? = nil
switch favoriteBook {
case .some(cleanCoder):
print("\(cleanCoder): Professionalism as a coder")
case .some(refactoring):
print("\(refactoring): How to improve your code")
case .some(let val):
print("You love another book: \(val)")
default:
print("You have no favorite book.")
}

Switch-statements: Check for ranges

let monthOfBirth = 11switch monthOfBirth {
case ..<7:
print("You are born in the first half of the year")
case 7...12:
print("You are born in the second half of the year")
default:
print("That's not a valid month!")
}
  1. We check for a range that is less than 7 (July) with ..<7.
  2. Then we check if the in the second case if the value is between 7 and 12 by using 7…12.
  3. Lastly, we cover the default case. It’s not enough that we know, that these values will never be above 12. The Swift compiler doesn’t know that. He only sees an integer and that means it could be a much bigger range than 1–12. The switch wouldn’t be exhaustive, that’s why we need a default-case.

Switch-statements: Do I need a default-case?

let isRaining = falseswitch isRaining {
case true:
print("Get my umbrella!")
case false:
print("Get my sunglasses")
}
let yourAnswerToTheMeaningOfLife = 42switch yourAnswerToTheMeaningOfLife {
case 42:
print("That's true 42 is the answer to the question of life")
default:
print("No that's wrong! It's 42!")
}
The error says: ‘Swift must be exhaustive`.

Summary

  1. If-statements run the code in their block when their condition evaluates to true. They can have an additional else-if-statement that checks if another condition is true and runs its code if that's the case. If none of the if- and else-if-statements evaluated to true, the optional else case would run.
  2. The if-let-statement works like an if-statement but creates an optional binding. If the optional has a value, the code of the if-let will run and the value is unwrapped in the conditional binding constant.
  3. The guard-statement acts like a bouncer. It will only let you continue to run the code in the scope if the condition evaluates to true. It has always an else-case in which the code must exit (with return, continue, break, or throw).
  4. The guard-let-statement also creates an optional binding. If the optional has a value, it will skip the guard’s else and run the code that follows. You can use the constant of the optional binding to have the value unwrapped until you reach the end of the scope.
  5. The ??-operator allows you to provide default values, for the case that the operand on the left is nil.
  6. The ternary operator lets you inline a conditional assignment where you want to use one of two values.
  7. The switch statement lets you check for equality of the expression/value with different cases. You don’t need a break in the cases to avoid a falling through in Swift. Swift will always only run the code in the case that was matched. You can (and oftentimes have to) provide a default case, that will execute some code when no case was evaluated to true.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Manuel Schulze

iOS developer from Germany who works as a contractor. Learning new things daily. Teaching Swift, iOS, macOS, watchOS, iPadOS, and tvOS programming.