SwiftUI extensions using generic type constraints
Discover page available: SwiftUIMost 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.