avatarSwiftos

Summary

The article discusses seven Swift keywords—fallthrough, inout, indirect, associatedtype, subscript, typealias, and operator—that can enhance code efficiency and functionality.

Abstract

The article "7 Powerful Keywords to Streamline Your Swift Code" by Dylan C. Fei on Medium provides insights into advanced Swift programming concepts. It explains how developers can use specific keywords to improve code structure and performance. The fallthrough keyword is demonstrated in a weather app scenario to avoid code duplication in switch-case statements. The inout keyword is highlighted for its ability to modify function parameters directly. The indirect keyword is shown to allow recursive enumerations without causing infinite compilation sizes. The associatedtype keyword is discussed for creating generic protocols that can work with any data type. The subscript keyword is presented as a way to create custom subscripts for safer array access. The typealias keyword is suggested for defining custom data types as shorthand for complex types. Lastly, the operator keyword is explained for creating custom operators to perform unique operations within the code. The article encourages Swift developers to explore these keywords to write more concise and powerful code.

Opinions

  • The author believes that using fallthrough can lead to more efficient code by reducing repetition in switch-case scenarios.
  • The use of inout is seen as a practical solution for modifying the parameters of a function, which can be particularly useful for maintaining state in functional programming contexts.
  • The indirect keyword is considered essential for creating enumerations with associated values that reference the enumeration itself.
  • Associatedtype is regarded as a powerful tool for protocol-oriented programming, allowing for flexible and reusable code.
  • The custom subscripts enabled by the subscript keyword are viewed as a way to prevent app crashes due to out-of-range array access.
  • The author suggests that typealias can be a convenient alternative to creating structures or classes for simple type abstractions.
  • Custom operators created with the operator keyword are seen as a feature that can make code more expressive and tailored to specific business logic.
  • The article concludes by recommending that developers familiarize themselves with these keywords to elevate their Swift code to a higher level of sophistication.

7 Powerful Keywords to Streamline Your Swift Code

Photo by Jon Tyson on Unsplash

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:

  1. If the user is suspicious, we will sign him/her out;
  2. If the user is unauthorized, we will sign him/her in, retrieve the location and the weather;
  3. 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 = .unauthorized
switch 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()
    fallthrough
case .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]) // nil

The 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 = Int
let myInteger: MyInteger = 123

You 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 = 3
print(||numberOne) // -3
print(||numberTwo) // -3

Infix 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) // 6

Postfix 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++) // 20

Conclusion

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.

Medium Claps — Made in Flinto by Thuy Gia Nguyen on Dribbble

Please clap if you enjoyed this article. Follow me. I’ll see you in subsequent articles :)

YOU MAY ALSO BE INTERESTED IN:

iOS App Development
iOS
Swift Programming
Swift
iOS Development
Recommended from ReadMedium