- In Swift, there are three kinds of statements: simple statements, compiler control statements, and control flow statements.
- Simple statements are the most common and consist of either an expression or a declaration.
- Compiler control statements allow the program to change aspects of the compiler’s behavior and include a conditional compilation block and a line control statement.
- Control flow statements are used to control the flow of execution in a program.
- There are several types of control flow statements in Swift, including loop statements, branch statements, and control transfer statements.
- Loop statements allow a block of code to be executed repeatedly, branch statements allow a certain block of code to be executed only when certain conditions are met, and control transfer statements provide a way to alter the order in which code is executed.
- In addition, Swift provides a
do
statement to introduce scope, and catch and handle errors, and adefer
statement for running cleanup actions just before the current scope exits.
1. Loop Statements
- Loop statements allow a block of code to be executed repeatedly, depending on the conditions specified in the loop.
- Swift has three loop statements: a
for-in
statement, awhile
statement, and arepeat-while
statement. - Control flow in a loop statement can be changed by a
break
statement and acontinue
statement.
1.1 For-In Statement
-
A
for-in
statement allows a block of code to be executed once for each item in a collection (or any type) that conforms to theSequence
protocol. -
A
for-in
statement has the following form:
for item in collection {
statements
}
let names = ["Anna", "Alex", "Brian", "Jack"]
for name in names {
print("Hello, \(name)!")
}
/* prints
Hello, Anna!
Hello, Alex!
Hello, Brian!
Hello, Jack! */
- You can also iterate over a dictionary to access its key-value pairs.
- Each item in the dictionary is returned as a
(key, value)
tuple when the dictionary is iterated, and you can decompose the(key, value)
tuple’s members as explicitly named constants for use within the body of the for-in loop.
let numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
for (animalName, legCount) in numberOfLegs {
print("\(animalName)s have \(legCountYou can also use `for-in` loops with numeric ranges.) legs")
}
/* prints:
spiders have 8 legs
ants have 6 legs
cats have 4 legs */
- You can also use
for-in
loops with numeric ranges.
for index in 1...5 {
print("\(index) * 5 is \(index * 5)")
}
/* prints:
1 * 5
2 * 10
3 * 15
4 * 20
5 * 25 */
- If you don’t need each value from a sequence, you can ignore the values by using an underscore
_
in place of a variable name.
let base = 3
let power = 10
var answer = 1
for _ in 1...power {
answer *= base
}
print("\(base) ^ \(power)ss = \(answer)")
/* results:
3 ^ 10 = 59049 */
- stride(from:to:by:) - Returns the sequence of values where last is the last value in the progression that is less than end.
- stride(from:to:by:) counts from the start point up to by excluding the to parameter.
for i in stride(from: 0, to: 10, by: 1) {
print(i)
}
/* prints:
0
1
2
3
4
5
6
7
8
9 */
- stride(from:through:by:) - counts from the start point up to by including the through parameter.
for i in stride(from: 0, through: 10, by: 1) {
print(i)
}
/* prints:
0
1
2
3
4
5
6
7
8
9
10 */
1.2. While Loops
-
A
while
loop performs a set of statements until a condition becomes false. -
These kinds of loops are best used when the number of iterations is not known before the first iteration begins.
-
Swift provides two kinds of
while
loops:while
evaluates its condition at the start of each pass through the loop.
while condition { statements }
repeat-while
evaluates its condition at the end of each pass through the loop.
repeat { statements } while condition
1.2.1 while
- A while statement is executed as follows:
- Step1: The condition is evaluated.
If true, execution continues to step 2. If false, the program is finished executing the while statement.
* Step2: The program executes the statements, and execution returns to step 1.
- Step1: The condition is evaluated.
var i:Int = 0
while i < 10 {
print(i)
i += 1
}
/* prints:
0
1
2
3
4
5
6
7
8
9 */
var title:String = ""
while title != "aaaaa" {
title = title + "a"
print(title)
}
/* prints:
a
aa
aaa
aaaa
aaaaa */
1.2.2 repeat-while
- A repeat-while statement is executed as follows:
- Step1: The program executes the statements, and execution continues to step 2.
- Step2: The condition is evaluated.
If true, execution returns to step 1. If false, the program is finished executing the repeat-while statement.
var j: Int = 10
repeat {
print(j)
}
while(j < 10)
/* prints:
10 */
2. Branch Statements
- Branch statements allow the program to execute certain parts of code depending on the value of one or more conditions.
- The values of the conditions specified in a branch statement control how the program branches and, therefore, what block of code is executed.
- Swift has three branch statements:
- an
if
statement - a
guard
statement - a
switch
statement.
- an
2.1 if-else
-
An
if
statement is used for executing code based on the evaluation of one or more conditions. -
There are two basic forms of an if statement. In each form, the opening and closing braces are required.
- The first form allows code to be executed only when a condition is true and has the following form:
if condition { statements }
- The second form of an if statement provides an additional else clause and is used for executing one part of code when the condition is true and another part of code when the same condition is false. When a single else clause is present, an if statement has the following form:
if condition { statements to execute if condition is true } else { statements to execute if condition is false }
-
if-else example:
var numArray = [10, 20, 30, 40, 50, 60, 70]
if(numArray.contains(20)){
print("true it contains 20")
}else{
print("number is not there")
}
/* prints:
true it contains 20 */
2.2 Guard
- A
guard
statement is used to transfer program control out of a scope if one or more conditions aren’t met. - A guard statement has the following form:
guard condition else {
statements
}
- The value of any condition in a
guard
statement must be of typeBool
or a type bridged toBool
. - The condition can also be an optional binding declaration.
let optionalNumArray: [Int?]
optionalNumArray = [1, 2, nil, 4, 5]
for num in optionalNumArray{
guard let num = num else{
print(":)")
continue
}
print(num)
}
/* prints:
1
2
:)
4
5 */
-
The
else
clause of aguard
statement is required, and must either call a function with the Never return type or transfer program control outside the guard statement’s enclosing scope using one of the following statements:- return
- break
- continue
- throw
2.3 Switch
- A
switch
statement allows certain blocks of code to be executed depending on the value of a control expression. - A switch statement provides an alternative to the if statement for responding to multiple potential states.
- A switch statement considers a value and compares it against several possible matching patterns. It then executes an appropriate block of code, based on the first pattern that matches successfully.
switch some value to consider {
case value 1:
respond to value 1
case value 2,
value 3:
respond to value 2 or 3
default:
otherwise, do something else
}
var grade = 45
switch grade {
case 90 ..< 100:
print("A")
case (80 ..< 90):
print("B")
case (70 ..< 80):
print("C")
case (0 ..< 70):
print("D")
default:
print("F. You failed")//Any number less than 0 or greater than 99
}
//prints: D
2.3.1 Interval Matching in switch
- Values in switch cases can be checked for their inclusion in an interval.
let approximateCount = 62
let countedThings = "moons orbiting Saturn"
let naturalCount: String
switch approximateCount {
case 0:
naturalCount = "no"
case 1..<5:
naturalCount = "a few"
case 5..<12:
naturalCount = "several"
case 12..<100:
naturalCount = "dozens of"
case 100..<1000:
naturalCount = "hundreds of"
default:
naturalCount = "many"
}
print("There are \(naturalCount) \(countedThings).")
// prints: There are dozens of moons orbiting Saturn.
2.3.2 Tuples in switch
- You can use tuples to test multiple values in the same switch statement.
- Each element of the tuple can be tested against a different value or interval of values. Alternatively, use the underscore character (_), also known as the wildcard pattern, to match any possible value.
let somePoint = (1, 1)
switch somePoint {
case (0, 0):
print("\(somePoint) is at the origin")
case (_, 0):
print("\(somePoint) is on the x-axis")
case (0, _):
print("\(somePoint) is on the y-axis")
case (-2...2, -2...2):
print("\(somePoint) is inside the box")
default:
print("\(somePoint) is outside of the box")
}
/* prints
(1, 1) is inside the box */
2.3.3. Value Bindings in switch
- A
switch
case can name the value or values it matches to temporary constants or variables, for use in the body of the case.
let anotherPoint = (2, 0)
switch anotherPoint {
case (let x, 0):
print("on the x-axis with an x value of \(x)")
case (0, let y):
print("on the y-axis with a y value of \(y)")
case let (x, y):
print("somewhere else at (\(x), \(y))")
}
/* prints:
on the x-axis with an x value of 2 */
2.3.4 Where in switch
- A
switch
case can use a where clause to check for additional conditions.
let yetAnotherPoint = (1, -1)
switch yetAnotherPoint {
case let (x, y) where x == y:
print("(\(x), \(y)) is on the line x == y")
case let (x, y) where x == -y:
print("(\(x), \(y)) is on the line x == -y")
case let (x, y):
print("(\(x), \(y)) is just some arbitrary point")
}
/* prints:
(1, -1) is on the line x == -y */
2.3.5 Compound Cases in switch
- Multiple switch cases that share the same body can be combined by writing several patterns after case, with a comma between each of the patterns.
- If any of the patterns match, then the case is considered to match.
let someCharacter: Character = "e"
switch someCharacter {
case "a", "e", "i", "o", "u":
print("\(someCharacter) is a vowel")
case "b", "c", "d", "f", "g", "h", "j", "k", "l", "m",
"n", "p", "q", "r", "s", "t", "v", "w", "x", "y", "z":
print("\(someCharacter) is a consonant")
default:
print("\(someCharacter) is not a vowel or a consonant")
}
/* prints:
e is a vowel */
3. Control Transfer Statements
- Control transfer statements change the order in which your code is executed, by transferring control from one piece of code to another.
- Swift has five control transfer statements:
- continue
- break
- fallthrough
- return
- throw
3.1 Continue
- The
continue
statement tells a loop to stop what it is doing and start again at the beginning of the next iteration through the loop.
let numbersArray = [20, 30, 40, 50, 60, 70, 80, 90, 10]
for num in numbersArray{
if(num > 10){
continue
}
print(num)
}
// prints: 10
3.2 Break
- The
break
statement ends execution of an entire control flow statement immediately. - The
break
statement can be used inside a switch or loop statement when you want to terminate the execution of the switch or loop statement earlier than would otherwise be the case.
if
let numbersArray = [20, 30, 40, 50, 60, 70, 80, 90, 10]
for num in numbersArray{
if num > 30{
break
}
print(num)
}
/* prints:
20
30 */
switch
for num in numbersArray{
switch num {
case 10:
print(num)
case 20:
print(num)
case 30:
break
default:
print("nothing here")
}
}
/* prints:
20
nothing here
nothing here
nothing here
nothing here
nothing here
nothing here
10 */
3.3 Fallthrough
- switch statements don’t
fallthrough
the bottom of each case and into the next one. That is, the entire switch statement completes its execution as soon as the first matching case is completed.
for num in numbersArray{
switch num {
case 10:
print(num)
case 20:
print(num)
case 30:
print(num)
fallthrough
case 40:
print(num)
default:
print("nothing here")
}
}
/* prints:
20
30
30
40
nothing here
nothing here
nothing here
nothing here
nothing here
10 */
3.4 return
- Generally in swift we use
return
statement in functions or methods to return the values based on our requirements. - By using
return
keyword we can return values from functions / methods based on our requirements in swift programming language.
return expression
func printA(a: String) -> String{
return a
}
print(printA(a: "abc"))
// prints: abc
return
func myFunc() -> Int {
let myNumber = 16 % 3
if myNumber == 0 {
return 0
}
else if myNumber == 1 {
return 1
}
return 0
}
// prints: 1
3.5 throw
enum VendingMachineError: Error {
case invalidSelection
case insufficientFunds(coinsNeeded: Int)
case outOfStock
}
struct Item {
var price: Int
var count: Int
}
class VendingMachine {
var inventory = [
"Candy Bar": Item(price: 12, count: 7),
"Chips": Item(price: 10, count: 4),
"Pretzels": Item(price: 7, count: 11)
]
var coinsDeposited = 0
func vend(itemNamed name: String) throws {
guard let item = inventory[name] else {
throw VendingMachineError.invalidSelection
}
guard item.count > 0 else {
throw VendingMachineError.outOfStock
}
guard item.price <= coinsDeposited else {
throw VendingMachineError.insufficientFunds(coinsNeeded: item.price - coinsDeposited)
}
coinsDeposited -= item.price
var newItem = item
newItem.count -= 1
inventory[name] = newItem
print("Dispensing \(name)")
}
}
let favoriteSnacks = [
"Alice": "Chips",
"Bob": "Licorice",
"Eve": "Pretzels",
]
func buyFavoriteSnack(person: String, vendingMachine: VendingMachine) throws {
let snackName = favoriteSnacks[person] ?? "Candy Bar"
try vendingMachine.vend(itemNamed: snackName)
}
struct PurchasedSnack {
let name: String
init(name: String, vendingMachine: VendingMachine) throws {
try vendingMachine.vend(itemNamed: name)
self.name = name
}
}
var vendingMachine = VendingMachine()
vendingMachine.coinsDeposited = 8
do {
try buyFavoriteSnack(person: "Alice", vendingMachine: vendingMachine)
} catch VendingMachineError.invalidSelection {
print("Invalid Selection.")
} catch VendingMachineError.outOfStock {
print("Out of Stock.")
} catch VendingMachineError.insufficientFunds(let coinsNeeded) {
print("Insufficient funds. Please insert an additional \(coinsNeeded) coins.")
}
// prints: Insufficient funds. Please insert an additional 2 coins.