Tutorials › Launch Lab Notes › Chapter 18

Down the Tree, Up the Tree

LabChapter 18 of the Launch Lab Notes20 minAugust 19, 2026Intermediate

SwiftUI talks in two directions.

Down the tree: a parent writes a value into the environment and descendants read it. Up the tree: children publish measurements through a PreferenceKey and an ancestor rolls them up. This bench runs both on one screen and puts a control next to each.

Filmstrip: accent cycles mint→rose→violet on WITH while WITHOUT stays gray; preference sum stays 168 from keys A,B.

Down — mint

.environment(\.harborAccent, accent.color)
 
struct WithAccentLeaf: View {
  @Environment(\.harborAccent) private var accent
  // …
}
PHASE DOWN accent mint. DOWN MINT. UP 168 pt, 2 chips. WITH mint border; WITHOUT gray. sum 168 · keys A,B. App 72, Build 96, Mute MUTE.
DirectionObserved
DOWNMINT — WITH border follows; WITHOUT stays gray
UP168 pt · 2 chips · keys A,B

App reports 72, Build 96, Mute shows MUTE. 72 + 96 = 168.

Down — rose (same control)

PHASE DOWN accent rose. DOWN ROSE. WITH rose border; WITHOUT still gray hard-coded control. UP still 168 pt.

DOWN ROSE. WITH picks up the new accent. WITHOUT is still the hard-coded gray control — it never asked @Environment(\.harborAccent).

Custom EnvironmentKey

HarborAccentKey supplies a default (Lab.dim). .environment(\.harborAccent,) overrides it for that subtree. @Environment(\.harborAccent) subscribes. No prop drilling.

Up — the roll-up

PHASE UP. UP 168 pt, 2 chips reported. sum 168 · keys A,B. Mute chip labeled MUTE.
.preference(key: ChipWidthKey.self, value: [id: geo.size.width])
 
.onPreferenceChange(ChipWidthKey.self) { reported = $0 }
ChipWidthReports?
App (A)72yes
Build (B)96yes
Mute—no (control)

Observed roll-up: sum 168 · keys A,B. Mute never enters the dictionary.

Both directions at once

PHASE BOTH accent violet. DOWN VIOLET. UP 168 pt. WITH violet; WITHOUT gray; Mute still MUTE.

PHASE BOTH, accent violet. DOWN card VIOLET, UP card still 168 pt / 2 chips. The two pipes do not fight — environment and preferences are different channels.

Mute is the preference control

If every child reported, you would not see the reduce step fail open. Leaving Mute out of ChipWidthKey makes the short total visible: 72 + 96, not 72 + 96 + 88.

Mini-exercise

Set reports: true on Mute. Re-run. The UP card should move to 256 pt (168 + 88) and keys should include C.

Challenges

  1. Add a second custom environment value (harborTitle) and show WITH reading both.
  2. Change ChipWidthKey.reduce to keep the max width instead of merging all keys — photograph the new UP number.
  3. Use anchorPreference to lift a chip's center and draw a line from the parent header to it.
  4. Inject .environment(\.harborAccent, .orange) only around WITH and prove WITHOUT still gray while a nested grandchild of WITH turns orange.
  5. XCUITest: after -mode rose, assert text contains ROSE and 168.

Key Points

Next up: custom Layout — a flow layout against Layout, printing the ProposedViewSize it receives and what each subview answers.

SwiftUI
SwiftUI tutorials for building native app screens, layouts, navigation, and state-driven interfaces.
Swift
Swift fundamentals for app developers who want to understand the language behind real iOS and macOS apps.
Ship iOS
Shipping workflows for iOS apps.
📚 Go deeper with LIPAI WANG’s hands-on Udemy bootcampsBrowse all courses →
← Ch 17: Who Won the DragCh 19: What the Subviews Answered→
SwiftUIUltimate SwiftUI SeriesSwiftUI tutorials for building native app screens, layouts, navigation, and state-driven interfaces.SwiftUltimate Swift SeriesSwift fundamentals for app developers who want to understand the language behind real iOS and macOS apps.Ship iOSShip iOS Apps SeriesShipping workflows for iOS apps: signing, TestFlight, App Store Connect, CI, and release hygiene.

Ship your apps faster

When you're ready to publish your Swift app to the App Store, Simple App Shipper handles metadata, screenshots, TestFlight, and submissions — all in one place.

Try Simple App Shipper
5 free articles remainingSubscribe for unlimited access