SwiftUI notes

Andy Brown · 01/07/2024 · 1 min read


Implicit Identity

Gotcha 1

Be careful when using something like this:

extension View {
    @ViewBuilder
    func applyIf<V: View>(_ condition: Bool, transform: (Self) -> V) -> some View {
        if condition {
            transform(self)
        } else {
            self
        }
    }
}

HStack {
    Image(systemName: "hand.wave")
    Text("Hello")
        .applyIf(highlighted) {
            $0.background(.yellow)
        }
}

This introduces a ConditionalContent with two subviews into the view tree: an unmodified text, and a text with a background. This means that when highlighed changes, the identity of the text onscreen will change as well.

This isn't good since the branch in the view tree might have unforseen consequences downsteam. A couple of examples:

  • When the identity of the view changes, SwiftUI treats the view as a new instance, which can cause unwanted behaviour like losing the view's state. For example, if using a TextField within a conditionally modified view, changing the condition might reset the state.
  • Conditional branches can introduce unnecessary complexity and overhead since SwiftUI has to recompute the view hierarchy every time the condition changes.
  • Conditional views can lead to layout inconsistencies since SwiftUI recalculates layouts based on the view hierarchies and any change in the condition might cause unexpected layout shifts, causing visual glitches or unwanted animations.

This is much safer since the background always has the same implicit identity.

HStack {
    Image(systemName: "hand.wave")
    Text("Hello")
        .background(highlighted ? .red : .clear)
}

Thinking in SwiftUI, Page 19


Discussions

Login to Post Comments
No Comments Posted