Using protocols to simplify SwiftUI

Daily Coding Tip 004

Protocol-oriented programming allows us to work more directly with value types, such as structures, instead of reference types like classes. Structures cannot inherit from a supertype, and so they do not inherit any attributes from an ancestor. SwiftUI relies on conformance to the View protocol instead, which specifies attributes for a specific purpose. Our View structure can’t inherit from a superclass, but we can still separate concerns by breaking it down into protocols and extensions.

import SwiftUI
protocol TextDisplayable: View {
var text: String { get }
}
struct TextView: TextDisplayable {
let text: String
}
extension TextView {
var body: some View {
Text(text)
}
}

This is the simplest possible example, but it shows a new way of constructing SwiftUI that separates the body property from the rest of the structure. Our protocol TextDisplayable conforms to the View protocol itself, leading to a chain of conformance that passes to the TextView structure. This is still conformance, NOT inheritance! This is what allows me to use an extension of TextView to provide the body property, without specifying conformity. If I removed the conformity from the TextDisplayable protocol, I would need to specify it either in the TextView declaration or the extension that contains the body.

Using protocols in this way allows our structure to contain nothing but the text property it requires. The only limitation of extensions is that they cannot contain stored properties, with the exception of computed properties as is the case with the body. If you decide to use this approach to SwiftUI, try to specify the purpose of your protocols as precisely as possible.

The standard suffixes for protocol names are -ible, -able and -ing, although in most cases one of them is sufficient to use consistently.


Get more Daily Coding Tips in your inbox!