Saurabh 😎

WWDC 2021: Demystify SwiftUI

3 main concepts: Identity, Lifetime, and Dependencies

Identity

Identity answers the question: are two views the same or different?
e.g. answer determines whether transition animation will fade in/out (two separate identities) or slide (same view with new position)

2 types of identity: explicit and implicit (aka structural)

Explicit identity - you have to assign the name

Implicit/structural identity - identity based on type and position in view hierarchy

AnyView is the evil nemesis of structural identity since it is a type erasing type - it hides the actual type from SwiftUI's type system

Lifetime

Views are value types - so identity refers to the "same" view with different values over time
Even though views themselves are values, any internal @State get memory allocated for them

Key idea: state lifetime = view lifetime

Use Identifiable protocol and its id property to tie data lifetime to views

Dependencies

Dependency graph - graph of dependencies between views and states/values

SwiftUI will refresh a dependency by getting the new .body
Value comparison used to cut down on .body calls

Identity is backbone of the graph

Kinds of dependencies - @Binding, @Environment, @State, @StateObject, @ObservedObject, @EnvironmentObject

Identifier stability - since state lifetime = view lifetime, the identifier is directly related to the view's lifetime
You should try to minimize identifier churn - use IDs stored persistently in a database instead of using a random ID every time

Identifier uniqueness - every ID should map to a unique view

Note that if date < .now { content.opacity(0.3) } else { content } is two views with different structural identities
Can push down conditional into opacity modifier: content.opacity(date < .now ? 0.3 : 1.0)
Key "trick" is the opacity(1.0) inert modifier which SwiftUI will just remove before rendering (since inert modifiers by definition have no effect on view)
Others: padding(0), transformEnvironment(...) { }