Weekly Swift articles, podcasts and tips by John Sundell.

SwiftUI extensions using generic type constraints

Published on 17 Jul 2020
Basics article available: SwiftUI

Most SwiftUI views that act as containers for other views are implemented as generics over the type of content that they contain. For example, SwiftUI’s built-in Button has a generic Label type that determines what type of view that each instance will be rendered using:

struct Button<Label>: View where Label: View {
    ...
}

Since SwiftUI views are, at the end of the day, just regular structs, we can use the same type of generic programming techniques when working with them as we can within other contexts. For example, we can use generic constraints to implement specialized convenience APIs — like this one that makes it easy to create a Button by using a given system image as its icon:

extension Button where Label == Image {
    init(iconName: String, action: @escaping () -> Void) {
        self.init(action: action) {
            Image(systemName: iconName)
        }
    }
}

The cool thing about generic type constraints is that the compiler will automatically infer what specialization to use based on each call site — meaning that we can call our new Button convenience initializer without having to manually type out Button<Image> when doing so:

struct PlayerView: View {
    ...

    var body: some View {
        ...
        Button(iconName: "play.fill") {
            startPlayback()
        }
    }
}

The fact that SwiftUI makes such heavy use of Swift’s type system and its generics capabilities means that there’s often a lot of opportunities to create very lightweight convenience APIs without having to define a new View type every time.

Support Swift by Sundell by checking out this sponsor:

Instabug
Instabug

Instabug: Investigate, diagnose and resolve issues up to four times faster. Whether it’s a crash, slow screen transitions, slow network calls or unresponsive UIs, Instabug lets you utilize powerful performance patterns to trace the cause of each issue. Detect if a specific app version, device or network connection is affecting the user experience and spot trends and spikes. Get started now and ship apps that your users will love.