7 Powerful Keywords to Streamline Your Swift Code
Hi iOS Developers,
In one of my previous articles, I discussed some powerful protocols to take your code to the next level. Today, I’m going to tell you about some handy keywords to streamline your code. Please check out my previous article if you are interested, Long story short, let’s jump right into it.
fallthrough
In general, the switch statement only executes one case. If we want to continue the execution to the next case, we can use the fallthrough keyword. Here’s an example:
Let’s say we’re developing a weather app. We need to check the authorization status. Based on what we find out about status, here’s what we’ll do:
- If the user is suspicious, we will sign him/her out;
- If the user is unauthorized, we will sign him/her in, retrieve the location and the weather;
- If the user is authorized, we will retrieve the location and the weather.
Let’s see what we’d do if we didn’t have the fallthrough keyword.
enum AuthStatus {
case authorized, suspicious, unauthorized
}let authStatus: AuthStatus = .unauthorizedswitch authStatus {
case .suspicious:
signOut()case .unauthorized:
signIn()
getLocation()
getWeather()case .authorized:
getLocation()
getWeather()
}As you can see, we have some duplicated code here, the getLocation and the getWeather because we need them both.
Let’s see how the fallthrough keyword helps to make the code more efficient.
switch authStatus {
case .suspicious:
signOut()case .unauthorized:
signIn()
fallthroughcase .authorized:
getLocation()
getWeather()
}Now, after executing the signIn, fallthrough allows the execution to continue to the next case which is the case .authorized.
inout
The inout keyword allows the code to change the value of parameters. Parameters are constants, which means we can’t change their value. But in some scenarios, we would like to change the parameter’s value. We can use the inout keyword for that.
For example:
We have an article app, so we need to update the UI and database every time we add new readers to the Article object. Without the inout keyword, you can see that we are having to call the refreshUI and storeToCoreData methods multiple times, which is very inefficient. Of course, you can use Combine or key-value observation.
Without inout :
struct Article {
var readers: [String]
}var article = Article(readers: [])article.readers.append("Dylan")
refreshUI()
storeToCoreData()article.readers.append("Mike")
refreshUI()
storeToCoreData()article.readers.append("Jenny")
refreshUI()
storeToCoreData()print(article.readers) /// ["Dylan", "Mike", "Jenny"]If you attempt to create a method like this, Xcode is going to resist you because the article is a constant and can’t be changed. Even if you could change the article, the changes won’t reflect the original object. Let’s try fixing this method.
func add(reader: String, to article: Article) {
article.readers.append(reader)
refreshUI()
storeToCoreData()
}With inout :
We need to add the inout keyword. It goes before the type. In the example below, we added the inout keyword before the type of article. This tells the program that we were going the change the value of article. And the changes will reflect the original object. When calling the method, we need to add & before article. Now, we can modify the article object in the method.
struct Article {
var readers: [String]
}var article = Article(readers: [])func add(reader: String, to article: inout Article) {
article.readers.append(reader)
refreshUI()
storeToCoreData()
}add(reader: "Dylan", to: &article)
add(reader: "Mike", to: &article)
add(reader: "Jenny", to: &article)print(article.readers) /// ["Dylan", "Mike", "Jenny"]indirect
The indirect keyword allows an enum to reference itself without becoming infinitely sized. Look at this example.
Let’s say we are developing a trip app, the app has an enum of cities and some cities may have a list of nearby cities. You will get a compilation error if you don’t create the enum with indirect.
indirect enum City {
case boston
case longIsland
case newYork(nearBy: [City])
}let boston: City = .boston
let longIsland: City = .longIsland
let newYork: City = .newYork(nearBy: [.boston, .longIsland])associatedtype
The associatedtype keyword allows us to create generic protocols, and we can also create a generic type within the protocols.
Without associatedtype
For example, if we need to create combination protocols to combine data, we also need to create one protocol for each type.
protocol NumberCombinable {
var numberOne: Double { get set }
var numberTwo: Double { get set }
func getCombination() -> Double
}protocol StringCombinable {
var stringOne: String { get set }
var stringTwo: String { get set }
func getCombination() -> String
}struct NumberCombination: NumberCombinable {
var numberOne: Double
var numberTwo: Double func getCombination() -> Double {
numberOne + numberTwo
}
}struct StringCombination: StringCombinable {
var stringOne: String
var stringTwo: String func getCombination() -> String {
stringOne + stringTwo
}
}With associatedtype
Now, we are able to create one generic protocol that fits all the cases.
protocol Combinable {
associatedtype CombinableData var dataOne: CombinableData { get set }
var dataTwo: CombinableData { get set } func getCombination() -> CombinableData
}struct NumberCombination: Combinable {
var dataOne: Double
var dataTwo: Double func getCombination() -> Double {
dataOne + dataTwo
}
}struct StringCombination: Combinable {
var dataOne: String
var dataTwo: String func getCombination() -> String {
dataOne + dataTwo
}
}subscript
The subscript keyword allows us to create custom subscripts. The most commonly used-case prevents an array from crashing the app. In Swift, if we try to retrieve an element with an index that’s out of range, the app will crash. We can use the handy subscript keyword to create a custom subscript that returns nil if the index is out of range.
extension Array {
subscript(from index: Int) -> Element? {
if index >= 0, index < count {
return self[index]
} else {
return nil
}
}
}let names: [String] = ["Dylan"]print(names[from: 2]) // nilThe index of 2, in this case, is out of range, but the app won’t crash because this custom subscript(from index: Int) -> Element? returns an optional element.
typealias
In comparison to the other keywords discussed above, this one is not all that useful, but it’s still good to know about. The typealias keyword allows us to easily create custom data types. Even though it is recommended to create custom data types with structs and classes, but sometimes it’s a kind of a waste of time to create a struct or class with not much usage.
Bad example:
struct MyInteger {
let integer: Int
}let myInteger = MyInteger(integer: 123)Good example:
Now, we can use the MyInteger the same way as Int. It’s a matter of personal preference if you want to create a type with a custom name from Int.
typealias MyInteger = Intlet myInteger: MyInteger = 123You can create more custom types with typealias . For example,
Tuple
typealias Address = (address1: String, address2: String, city: String, state: String, zip: Int)let address = Address(address1: "", address2: "", city: "", state: "", zip: 123)Array
typealias MyAddress = [Address]let addresses = MyAddress()operator
The operator keyword allows data to perform operations. For example, the + operator can perform addition, such as 1 + 3 equals 4.
We can create custom operators to support our business logic.
Prefix Operators
Prefix operators are used before the operand.
Let’s create a prefix operator to get the negative of the absolute value of an integer.
prefix operator ||prefix func ||(rhs: Int) -> Int {
-abs(rhs)
}let numberOne = -3
let numberTwo = 3print(||numberOne) // -3
print(||numberTwo) // -3Infix Operators
Infix operators are used between the operands.
Let’s create an infix operator to subtract the value of the right-hand side twice.
infix operator --func --(lhs: Int, rhs: Int) -> Int {
lhs - (rhs + rhs)
}print(5 -- 1) // 3
print(10 -- 2) // 6Postfix Operators
Postfix operators are used after the operand.
Let’s create a postfix operator to double the value of an integer.
postfix operator ++postfix func ++(lhs: Int) -> Int {
lhs + lhs
}print(2++) // 4
print(10++) // 20Conclusion
There are only a few keywords in Swift, in comparison to the number of functions and properties. I highly recommend checking them out. A lot of them are super helpful, and they can really take your code to another level.






