Introduction To Swift: Basics (Part 3)

Introduction To Swift: Basics (Part 3)

Exploring loops and control flow statements in swift.

Swift has "if" and "switch" statements for executing code blocks based on conditions and "for-in" to iterate over arrays, ranges, and dictionaries, and "while" to perform operations multiple times until the condition is satisfied. Also, some control transfer statements like continue break, fallthrough, return and throw.

Looping

For-In Loop

We can use the for-in loop to iterate over items in an array, ranges of numbers, or characters in a string.

var colorsOfRainBow = ["Red", "orange", "yellow", "green", "blue", "indigo", "violet"]

for color in colorsOfRainBow {
    print(color)
}

In the above code snippet, the for-in loop is used to iterate over an array of color names. Let's see how we can iterate over range.

for index in 1...10 {
    print(index)
}

Here we defined a range from 1 to 10 using the closed range operator (...). When the loop will start executing index will get assigned the first value of the range i.e 1 and the code inside the loop will execute when the loop will complete the execution the next value will get assigned to index and this will continue until the range is over.

If you have no intention of using the value obtained while iterating you can use the underscore (_) instead of the variable name.

for _ in 1...10 {
    // code block
}

stride()

stride() from swift helps to move from one value to another in sequence/range by letting us specify step increment or decrement value and also gives the option if we want to include upper bound (end value of resulting sequence) or not.

There are two versions of stride provided by Swift:

  • stride(from start: T, to end: T, by stride: T.Stride):

Where start is the starting value to use for the sequence, end is an end value to limit the sequence, and stride is the value to step by with each iteration move. A positive value of stride means iteration happens upward and a negative stride value means iteration will happen downwards.

Let's see an example

for i in stride(from: 0, to: 5, by: 1){
    print(i)
}
/** output:
*   0   
*   1
*   2
*   3
*   4
*/

Here we defined a stride that starts from 0 and ends at 5 and the stride value is 1 which means iteration will happen upwards.

Negative stride example

Here we are passing a negative value as a stride to create a sequence from a higher start to a lower end.

for i in stride(from: 5, to: 0, by: -1){
    print(i)
}
/** output:
*   5   
*   4
*   3
*   2
*   1
*/

If you observe the output of both of the code snippets you will see it did not print the last value (end) of the sequence this is because if we use to: it excludes the end. So if we need the end value also we can use another version of stride.

  • stride(from start: T, through end: T, by stride: T.Stride):

This version of stride is the same as above one only difference is that it includes the end value also in the resulting sequence.

for i in stride(from: 0, through: 5, by: 1){
    print(i)
}
/** output:
*   0   
*   1
*   2
*   3
*   4
*   5
*/

Using through: instead of to: specifies that we want to include the end value.

While Loop

While

A while loop executes a block of code until a specified condition becomes false. while checks the specified condition at the start of each iteration through the loop and if it evaluates as true to execute the block and this keeps repeating until the condition evaluates as false.

Syntax

while(condition){
// code
}

Example

var start = 1
var end = 6

while(start <= end){
    print(start)
    start += 1
}

Here we defined two variables start and end and assigned initial values 1 and 6 respectively. Then next in the while loop we specified the condition as the start should be less than equal to the end then only execute the code block. Inside the block, we are printing the value of start and incrementing the value of start by 1. We are incrementing the value of the start because at some point we want the while condition to evaluate as false to stop looping if we don't do this it will go in an infinite loop.

Repeat-While

In this version of the while loop first the block of code gets executed and then the condition is checked.

repeat {
   //code
} while (condition)

Example

var start = 1
var end = 6
repeat {
    print(start)
    start += 1
} while (start <= end)

In the above code first code inside the repeat block got executed and the then condition provided to while is evaluated.

Conditional Statements

Conditional Statements allow us to execute a specific part of code only if certain conditions are satisfied. Swift has conditional statements like an if statement and a switch statement.

if statement

An if statement is used for executing code based on the evaluation of one or more conditions.

Syntax:

if(condition){
   // execute code
}

if the condition evaluates as true then the code inside the block will execute otherwise it won’t. Suppose we want to execute a certain code if the condition is not true i.e. condition is false then in such case, we can use the else block.

if (condition){
   // condition is true then execute this
} else {
  // condition is false then execute this
}

Example

var isChargerConnectedToElectriciyBoard = true
var isDeviceConnectedToCharger = false

if isChargerConnectedToElectriciyBoard && isDeviceConnectedToCharger {
    print("Charging started")
} else {
    print("Can not charge device")
}

Here we want to print “Charging started” only if both isChargerConnectedToElectriciyBoard and isDeviceConnectedToCharger are true otherwise we print “Can not charge device”.

We can also chain multiple if statements together to evaluate multiple conditions like this

var currentBatteryPercentage = 14
var plugToChargerThresholdValue = 15
var maxChargingAllowed = 90


if currentBatteryPercentage <= plugToChargerThresholdValue {
    print("Plug device to charger")
} else if currentBatteryPercentage >= maxChargingAllowed {
    print("Device overcharged")
} else {
    print("Battery at optimal percentage")
}

In this example, we want to check the current battery percentage with different values and print the message informing us about the battery status. In the first If block we check if currentBatteryPercentage is less than equal to plugToChargerThresholdValue and if this condition evaluates as true it will print the message "Plug device to charger". But we also want to print a message informing that battery is overcharged and for that, we can add one more block using the else if clause. So we added one more condition to check if currentBatteryPercentage is greater than equal to maxChargingAllowedand if it evaluates as true then print the message "Device overcharged". And at the end, if both the above conditions do not evaluate as true then we print the message "Battery at optimal percentage" using the else clause. Also, even if we don't add the else block then also it is fine as the else clause is optional here and can be excluded.

Switch statement

A switch statement takes a value and compares it against the multiple possible cases and then executes an appropriate block of code, based on the first case matched correctly. The switch statement can be used instead of the if statement, when there are multiple conditions needed, to be evaluated.

Syntax:

switch value {
case value 1:
    // result for value 1
case value 2:
    // result for value 2
default:
    // if nothing matched then do something else
}

The switch statement consists of multiple possible cases, each of which begins with the case keyword. Each case is a separate branch of code execution. The switch statement determines which branch should be selected.

Every switch statement must be exhaustive.

The meaning of the above line is that for all possible values, there must be a matching switch case. if it’s not possible to provide a case for every possible value, then we can define a default case to cover any values that aren’t addressed explicitly. The default case is specified by the default keyword, and it should always be present at last.

Example:

var nameOfHero = "IronMan"

switch nameOfHero {
case "SpiderMan":
    print("web-shooters")
case  "CaptainAmerica":
    print("Enhanced strength, speed")
case "IronMan":
    print("The armor and weapons.")
default:
    print("Superhero")
}

In this example, the switch statement considers the value of the nameOfHero variable and has cases that match different names of superheroes and print their powers. Also, it has a default case that will execute if nameOfHero does not match with any defined cases.

If you ever saw a switch statement in other programming languages you will notice we are not using a break statement in swift to stop the flow as soon as the case match.

// switch in javaScript
switch(value) {
  case x:
    // code block
    break;
  case y:
    // code block
    break;
  default:
    // code block
}

In other languages, if we don't write a break at the end of the code block switch goes through all the following cases but this does not happen in swift instead the switch statement finishes its execution as soon as the first matching switch case is completed.

Control Transfer Statements

If you want to change the order of execution and transfer control from one block to another for that purpose you can use control transfer statements. Swift has five control transfer statements: continue, break, fallthrough, return and throw.

Continue

The continue statement tells a loop to stop the current iteration and start again at the beginning of the next iteration through the loop.

var colorsOfRainBow = ["red", "orange", "yellow", "green", "blue", "indigo", "violet"]

// for in loop
for color in colorsOfRainBow {
    if (color == "red") {
        continue //stop the iteration
    }
    print(color)
}

/**
Output: 
 orange
 yellow
 green
 blue
 indigo
 violet
 */

In the above example, we are looping over an array of rainbow colors named colorsOfRainBow by using for-in loop. Inside the loop, we are just printing the color but also there is an if statement that checks if the color in the current iteration is equal to "red" and if that statement evaluates true it will go inside the if block where continue is written which will stop current iteration there that means the print() won't execute and next iteration will start.

Break

The break statement ends the execution of an entire control flow statement immediately.

Break in a Loop Statement

When we use break statement inside a loop it immediately stops the execution of the loop and transfers the control outside the loop. No code from the current iteration or next iteration gets executed.

var colorsOfRainBow = ["Red", "orange", "yellow", "green", "blue", "indigo", "violet"]

// for in loop
for color in colorsOfRainBow {
    if (color == "yellow") {
        break
    }
    print(color)
}
print("After Loop executed")

/**
Output:

 red
 orange
 After Loop executed
 */

Using the same example as before here we just changed the if statement where we are checking if the color in the current iteration is equal to "yellow" and if this evaluates true then in the inside block we used break which will stop entire loop execution and will start using code written after for-in loop.

If you see the output of the above code it just prints 2 colors from an array and then when if the statement evaluates true it stopped for-in and executed print written after the loop.

Break in a Switch Statement

Same as loops when we use break statement inside a switch statement it immediately stops the execution of the switch and transfers the control outside the loop.

Fallthrough

As we saw in the switch statement section in swift even if we don't add break statement after each case swift stops the entire switch statement execution once the case matches successfully. But in some other programming, this won't happen if don't add break even if the switch case is matched it will go through the following cases. If we want to opt-in to that same kind of behavior in swift we can use fallthrough.

var nameOfHero = "SpiderMan"

switch nameOfHero {
case "SpiderMan":
    print("web-shooters")
case  "CaptainAmerica":
    print("Enhanced strength, speed")
    fallthrough
case "IronMan":
    print("The armor and weapons.")
default:
    print("Superhero")
}
/**
Output: 
Enhanced strength, speed
The armor and weapons.
 */

In the above example switch statement considers the value of nameOfHero and matches the cases against it. One additional change is we added fallthrough in one of the cases. Here the value of nameOfHero is CaptainAmerica when the switch case matches this value it will start executing a block of code for this case. Inside that block, we just added a simple print(), and then we added fallthrough keyword to fall into the next case also. When this fallthrough keyword is used without checking the case condition it will execute the next case block code. If you see the output of the above code you can notice it executed print from two cases.

Return

Inside a function, we can use the return keyword to send a value back if we have one. Then the function immediately exits, sending back that value. Any code which is written after return never gets executed.

func add(first: Int, second: Int) -> Int {
    return first + second
}

var result = add(first: 10, second: 20)
print(result)

In the above example add function is taking two params named first and second both of type integer and returning a value of type Interger. Inside the function, only the addition of both values is perfromed, and the resulting value after addition is returned. Next, that function is called with correct parameters, and the returned value is assigned to the variable result.

Throw

throws are used for propagating errors through throwing functions. Throwing functions are functions that are marked with throws.

Example:

enum MessageError: Error {
    case MinimumLength
}

func sayHi(name:String) throws -> String {
    if name.count < 2 {
        throw MessageError.MinimumLength
    }
    return "Hello \(name)"
}

sayHi(name: "A")

In the above example sayHi function is defined which takes a name as a parameter of the type string and returns the value of the type string. Also, we are marking this function as a throwing function by adding throws. Inside the function, we check for the length of the name, and if it is less than two then we throw an error MessageError.MinimumLength. throw works much like a return but it gives the error which needs to be handled and also once the error is thrown further execution of the function stops.