I’m going to go a bit old school on this one. We’re staying on Swift here, don’t worry, but I want to cover something that has been around since the early days of C. They were probably earlier, but that’s the oldest language besides BASIC that I personally have experience with. We’re going to talk about some classic control flow and how Swift has updated them… or kept them the same, we’ll see.
Standard For Loop
For-In Loop
When I learned about the equivalent in C#, I used these as often as I could. If I didn’t need to know the index for something, it was amazing. It basically lets you step through a range or collection and store whatever is at that index in a temporary variable that you can use in that loop iteration. So if we had an array and wanted to step through it:
let primeNumbers = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31] for number in primeNumbers { print("\(number)") }
That will just step through each number and print them out on a new line. It is quite simple.
For-In Loop with Ranges
It also works with ranges, and they have their own interesting new syntax. Ranges basically give you a shorthand for writing a series of numbers. The are pretty useful in for loops (shorter than a normal for loop, with less semicolons), but even better with Switch Statements
You have 2 Range Operators, closed and half-open.
- Closed Range Operator ” … ” – makes a range including the last number, so ” 0…3 ” is a range containing 0, 1, 2, and 3.
- Half-Open Range Operator ” ..< ” – makes a range excluding the last number, so ” 0 ..< 3 ” is a range containing 0, 1, and 2.
Half-Open used to have another operator, but I definitely like this one better. It basically is saying it is a range operator (with the “..”), but less than (with the “<“) the last number, like you would in many standard for loops. As such, to do an equivalent of our normal for loop from the first section, we would do this:
for index in 0..<3 { print(index) }
Since we used a half-open range, it steps through 0, 1, and 2.
If Statement
Much like the standard for loop, hasn’t changed much. There are two notable differences from C though. While I’m not certain if parentheses around the if-statement’s conditional were REQUIRED in C, the are most definitely not in Swift. In C though, the brackets surrounding the if-statement’s code block (what to execute if that condition is met) were not required. If you only needed 1 line of code to run, you could just say that, and use the indentation to make it more obvious to the reader. Thankfully though, the Swift team seems to agree with me that those curly-braces should be required for if-statement code blocks.
So just to be clear, in Swift, parentheses around the conditional are optional, but curly-braces around the code block are required. Other than those differences (which always good style in C anyway), the statement is pretty much the same, for example:
if someNumber > 0 { print("That is a positive number") } else if someNumber < 0 { print("That is a negative number") } else { print("That number is zero") }
Switch Statement
Unlike if statements, switch statements have had quite the update in Swift. The general syntax is very similar, but there are a few major differences, they are:
- Swift switch statements do not implicitly fall-through — In C, you had to use the keyword break to stop as you were done in each case. In Swift, the compiler knows that if it sees the next case statement, the one you are on has completed executing.
- Swift switch statements can match multiple cases on the same line — In Swift, you separate each value by a comma before the colon. In C, you could abuse the fall-through to do something similar here, but you would have a series of “case blah:” “case blah2:” listed, that just looks messy.
- Swift switch statements can match against ranges — Remember those ranges that I mentioned in the for-in section? They work here too, which is even cleaner than the multiple cases separated by commas mentioned above, if you have numeric values.
- Swift switch statements can have more complex cases via pattern matching — This is particularly useful when dealing with enumerations. Enumerations can have values associated with different enumeration cases, and you can bind those to variables here, or even have sub-cases dealing with that associated value. There is a lot to this aspect of switch statements, and also for enumerations. Both will be covered by future posts (Enumerations are covered in the future post Enumerations in Swift), but I wanted to mention it for the introduction to switch statements in Swift.
Switch statements in Swift must be exhaustive. They must contain all possible cases, otherwise the compiler will give an error. Of course you can use a default case so you don’t actually have to write each case all yourself if there are ones you really don’t care about, but it must be exhaustive, one way or another.
Other than the lack of requiring break, the switch statement actually looks pretty much the same as it did before. Even these new capabilities are done in ways that really look like they fit in with the old style and are just slight extensions to it (like comma separated case values).
Here’s a standard switch statement:
switch aNumber { case 1: print("uno") case 2: print("dos") case 3: print("tres") default: print("Something else") }
Here is a multiple value per case switch statement:
switch aNumber { case 0,2,4,6,8,10: print("This is an even number between 0 and 10") case 1, 3, 5, 7, 9: print("This is an odd number between 0 and 10") default: print("This number is not between 0 and 10") }
Here is a switch statement matching against ranges:
switch aNumber { case 0...5: print("This number is between 0 and 5") case 6...10: print("This number is between 6 and 10") default: print("This number is not between 0 and 10") }
As I said earlier, there is a lot to talk about in relation to pattern matching in switch statements, so instead of trying to squeeze it into an already long post, it will have its own post to explain that capability, Pattern Matching in Swift.
While and Repeat-While Loops
I will squeeze this in though. Much like the if statement, they did not change much. The only difference is that they do not need parenthesis around the conditional.
while i < 5 { print("\(i)") i += 1 }
Below is an example of a Repeat-While loop (formerly known as the Do-While loop):
var someOptionalInt: Int? = nil repeat { print("Trying to get an integer") someOptionalInt = functionThatMayReturnAnInteger() } while (someOptionalInt != nil) print("Got a nil instead")
As you see, here it tries to fill the “someOptionalInt” variable, and if it does, it keeps going. If it doesn’t, it will break out of the loop and tell the user that it got a nil instead. In this example, someOptionalInt started as nil, and it still went into the loop to try. Now, to do anything USEFUL safely with this value, you would have to test if it is nil inside the loop if you don’t want it to crash when trying to unwrap someOptionalInt. While that does mean you have to test twice, it also means that you only need to call your functionThatMayReturnAnInteger() function inside your loop. Otherwise, you would have to run it outside of the loop once, and then have to write it inside the loop again. I’m not the biggest fan of repeat-while loops, but they have their place.
Below is a quote from Stack Overflow (reformatted and slightly paraphrased) that sums up when you would use one or the other quite nicely:
- If it should run zero or more times, test at the beginning (While Loop)
- If it must run once or more, test at the end (Repeat-While Loop)
Conclusion
So, for a quick summary of the changes (or lack thereof):
Minor changes:
- If Statement – Same except no longer requires parenthesis around conditional, and curly-braces around code block are required.
- While or Repeat-While Loop – Same except no longer requires parenthesis around conditional.
Major changes:
- For-in Loop added – Step through each value in a collection or range and assign to a temporary variable to do work.
- Switch Statement – No more implicit fall-through, can match against multiple cases on same line, ranges, and patterns.
See my future post Enumerations in Swift for more information.
Check out this future post about Pattern Matching in Swift.
I hope you found this article helpful. If you did, please don’t hesitate to share this post on Twitter or your social media of choice, every share helps. Of course, if you have any questions, don’t hesitate to contact me on the Contact Page, or on Twitter @CodingExplorer, and I’ll see what I can do. Thanks!