Reading state
The runtime guarantees that a normal read is correct: it uses the latest completed turn and settles every dependency the value needs. What this chapter adds is a discipline for how reads look, so a reader of the code can see what a view or computation depends on without running it in their head.
Unwrap every read into a domain local
In application code and user-facing examples, bind each value-producing c[...], cogs[...], or status/peek read to a local before using it. Name the local by removing the declaration's final Cog or Cogs:
let selectedTab = c[selectedTabCog]
let tabPath = c[tabPathCogs[selectedTab]]
let savedTrailIDs = cogs[savedTrailIDsCog]For a status read, keep the same clean name. Do not add a Status suffix, even though the local's type is CogStatus:
let forecast = cogs.status[weatherForecastCogs[zip]]
if forecast.isLoading { … }Creating the local observes no field by itself, so SwiftUI still tracks only the fields the body actually uses. The rule applies in views, selectors, reactions, and operations. Three call shapes do not need a local: write targets (c[_selectedTabCog] = tab), calls that take a value reference (refresh(weatherForecastCogs[zip])), and low-level tests that isolate one exact read expression.
The payoff is a uniform vocabulary. selectedTabCog is always the reference. selectedTab is always the value. A reviewer never has to wonder which of the two a line is handling.
Read flatly; never repackage reads into a projection type
A view that needs several values reads each one on its own line and binds it to a domain local — however many there are. Do not gather them into a struct. Not one built by an initializer that takes Cogs, and not one built by a Cogs extension.
Such a type hurts three ways and helps none. It adds a layer you must open to learn what the view depends on. It invites being stored or passed onward. And it buys nothing: reads in one body already come from one settled turn, and each read already registers on its own, so unrelated turns invalidate nothing. If a value is genuinely derived rather than merely read together, declare an automatic cog and read that flatly too (Declaring state).
Tracked reads, one-time reads
Tracked reads use subscripts — c[…] inside a computation or reaction, cogs[…] in a view body — and register a dependency. One-time reads use peek. The value still settles, but no dependency and no Observation access is recorded.
Use peek where a dependency would be wrong: a mechanism reading during operate, a scope body checking state without re-triggering the scope, and test assertions (cogs.peek(savedTrailIDsCog)).
Async reads are total; uncertainty is opt-in
A normal read of an async declaration always returns a value: the last accepted success, or the declaration's default before one exists. Code that does not care about the request lifecycle reads the plain value and stays stable across reloads:
let weatherForecast = cogs[weatherForecastCogs[zip]] // last accepted, or nilCode that renders request chrome — spinners, error text — opts into the status lens. Read only the fields you need (kind, value, hasSucceeded, error, isLoading), because SwiftUI tracks each field separately:
let forecast = cogs.status[weatherForecastCogs[zip]]
if forecast.isLoading { ProgressView() }Keeping the two spellings separate keeps derived state calm. An automatic value computed from the plain read changes only when an accepted value does, not on every loading flicker.