struct ForEach
Swift
struct ForEach<Data, ID, Content> where Data : RandomAccessCollection, ID : Hashable, Content : View
Variable-length children with explicit key identity.
Fragment: children splice into the parent (inherits row/column).
No buildArray — plain for in builders is intentionally unsupported.
Children are built in init, not at mount time. That is a correctness
decision, not a performance one, and it is the whole reason this type looks
the way it does.
ViewNode.computeBody evaluates view.body inside
withObservationTracking, so a read registers a dependency only if it
happens while that call runs. When this type stored its content as an
@escaping closure and called it later — during mount and reconcile — every
observable read inside that closure landed outside the tracking scope and
subscribed to nothing. A row written as
ForEach(fits, id: \.value) { fit in
PickerRow(..., selected: store.fit == fit.value) // registers nothing
}
drew the right answer once and then never updated, while the same
comparison hoisted into body worked. LavaSettings shipped that bug on its
Background page: the wallpaper changed and the radio button did not move.
Deferring the closure could not be fixed by tracking it separately. The
closure captures the enclosing body's locals and data came from that body
too, so ForEachFragmentNode cannot regenerate children on its own — the
only correct response to such a dependency changing is "run the parent body
again", which is exactly what registering during the parent body already
means. Building here makes the reads happen in the parent body, where they
belong, and the trap becomes unwriteable rather than merely documented.
The cost is that every element's view value is built on each body pass.
Those are cheap structs; the retained work — nodes, Yoga, draw lists — is
still reconciled by key below, not rebuilt. Nothing in this repo feeds an
unbounded collection through here: the long lists cap themselves first
(prefix(visibleLimit)), and a terminal's scrollback or an editor's lines
never take this path at all.
Sources/LavaUI/ForEach.swift:40
Constructors
init(_ data: Data, id: KeyPath<Data.Element, ID>, @ViewBuilder content: (Data.Element) -> Content)
Not documented.
Sources/LavaUI/ForEach.swift:48
init(_ data: Data, @ViewBuilder content: (Data.Element) -> Content)
Not documented.
Sources/LavaUI/ForEach.swift:82
Properties
var dumpDetail: String { get }
Not documented.
Sources/LavaUI/ForEach.swift:56
var rows: [(id: ID, content: Content)]
One built child per element, in order, with the key it is identified by.
Sources/LavaUI/ForEach.swift:46
Methods
func mountPrimitive() -> any AnyViewNode
Not documented.
Sources/LavaUI/ForEach.swift:66
func reconcilePrimitive(_ node: any AnyViewNode) -> any AnyViewNode
Not documented.
Sources/LavaUI/ForEach.swift:72
func structureLines(indent: Int = 0) -> [String]
Not documented.
Sources/LavaUI/ForEach.swift:58