Articles Projects About Subscribe
Field Notes

Posts

Short-form iOS engineering insights — Swift, SwiftUI & the Apple platform, written from a senior perspective.

All posts

37
Jul 13, 2026

Dark mode regressions don’t show up as crashes—they ship as unreadable text on blurred cards and brand tints that vanish over images

Dark mode regressions don’t show up as crashes—they ship as unreadable text on blurred cards and brand tints that vanish over images. Most teams compute contrast again...

Post · 1 min
Post
Jul 6, 2026

A feed that jitters on device but “looks fine” in Simulator is often observation, not layout

A feed that jitters on device but “looks fine” in Simulator is often observation, not layout. I traced a scroll hitch to a single @Observable retained by two ancestors...

Post · 1 min
Post
Jul 2, 2026

Stacks and geometry hacks can introduce scroll jank; a purpose-built SwiftUI `Layout` can centralize the math and make results more predictable

Stacks and geometry hacks can introduce scroll jank; a purpose-built SwiftUI Layout can centralize the math and make results more predictable. Measure once,

Post · 1 min
Post
Jun 25, 2026

Cold starts regress, frames drop, and the trace looks “fine

Cold starts regress, frames drop, and the trace looks “fine.” Without precise, low-overhead markers on hot paths, you’re debugging timestamps and gut feel instead of t...

Post · 1 min
Post
Jun 22, 2026

Shortcuts shows one dialog, your logs insist another

Shortcuts shows one dialog, your logs insist another? You may be attached to the wrong process—or hitting @Parameter/EntityQuery timing differences. Trust what the Sho...

Post · 1 min
Post
Jun 18, 2026

Sign in with Apple outages during a domain change rarely come from Swift—they come from config

Sign in with Apple outages during a domain change rarely come from Swift—they come from config. And with Apple unifying relay addresses under private.icloud.com, auth ...

Post · 1 min
Post
Jun 15, 2026

On visionOS, navigation issues often show up at state boundaries—not just buttons

On visionOS, navigation issues often show up at state boundaries—not just buttons. When 2D windows, 3D spaces, and restoration drift, back gestures and focus can feel ...

Post · 1 min
Post
Jun 12, 2026

Toolchain bumps are an operational risk, not just a compiler upgrade — mismatched CI and local toolchains can introduce flaky PRs, signing issues, and stalled releases

Toolchain bumps are an operational risk, not just a compiler upgrade — mismatched CI and local toolchains can introduce flaky PRs, signing issues, and stalled releases...

Post · 1 min
Post
Jun 12, 2026

Migrations to `SwiftUI` and structured concurrency often compile cleanly but can expose timing, cancellation, and partial-write bugs only at runtime — plan for an operational rollout phase

Migrations to SwiftUI and structured concurrency often compile cleanly but can expose timing, cancellation, and partial-write bugs only at runtime — plan for an operat...

Post · 1 min
Post
Jun 12, 2026

Converting to modern SwiftUI often changes runtime behavior more than code size — cancellation, invalidation, and state restoration can surface in production if you treat this as a purely syntactic swap

Converting to modern SwiftUI often changes runtime behavior more than code size — cancellation, invalidation, and state restoration can surface in production if you tr...

Post · 1 min
Post
Jun 12, 2026

Converting callback-heavy networking to Swift Concurrency can push cancellation, isolation, and scheduling issues into production — many of these problems only appear under real load

Converting callback-heavy networking to Swift Concurrency can push cancellation, isolation, and scheduling issues into production — many of these problems only appear ...

Post · 1 min
Post
Jun 12, 2026

Renaming or reordering menus can silently break shortcuts, AppleScript/AppleEvent hooks, and assistive discovery — treat a menu redesign as a migration, not a string swap

Renaming or reordering menus can silently break shortcuts, AppleScript/AppleEvent hooks, and assistive discovery — treat a menu redesign as a migration, not a string s...

Post · 1 min
Post
Jun 11, 2026

A single shared observable can kill scroll performance: one mutation, many ancestors re-render, stuttery scrolling and layout shifts

A single shared observable can kill scroll performance: one mutation, many ancestors re-render, stuttery scrolling and layout shifts. Read \(.sizeCategory) as clos...

Post · 1 min
Post
Jun 9, 2026

Platform betas break timing and lifecycle assumptions — surface those breaks in a controlled pipeline before customers do

Platform betas break timing and lifecycle assumptions — surface those breaks in a controlled pipeline before customers do. Run a parallel CI lane (beta Xcode image...

Post · 1 min
Post
Jun 8, 2026

Converting callbacks to `async`/`await` is a semantics change — not just a syntax rewrite

Converting callbacks to async/await is a semantics change — not just a syntax rewrite. Cancellation, lifetimes, and concurrency boundaries can change runtime behavior ...

Post · 1 min
Post
Jun 4, 2026

Widening visibility in Swift packages can expand your ABI and increase the risk of small refactors causing runtime or binary incompatibilities

Widening visibility in Swift packages can expand your ABI and increase the risk of small refactors causing runtime or binary incompatibilities. Prefer internal by ...

Post · 1 min
Post
Jun 1, 2026

Short guidance gaps at crowded race starts can come from coaching logic running off-watch—phone or network dependencies can break continuity

Short guidance gaps at crowded race starts can come from coaching logic running off-watch—phone or network dependencies can break continuity. Make the watch the source...

Post · 1 min
Post
May 28, 2026

A SwiftUI canvas that looks perfect but VoiceOver only reads “group” usually means accessibility semantics or notifications were never made explicit — pixels aren’t the whole contract

A SwiftUI canvas that looks perfect but VoiceOver only reads “group” usually means accessibility semantics or notifications were never made explicit — pixels aren’t th...

Post · 1 min
Post
May 25, 2026

Cross-process intent decoding can silently break widget updates — treat `AppIntent` parameters as a durable API

Cross-process intent decoding can silently break widget updates — treat AppIntent parameters as a durable API. Prefer concrete types for intent parameters (Int, en...

Post · 1 min
Post
May 21, 2026

A frozen macOS window during a customer demo erodes trust instantly — many stubborn hangs only reproduce on device because the simulator’s environment differs

A frozen macOS window during a customer demo erodes trust instantly — many stubborn hangs only reproduce on device because the simulator’s environment differs. Sta...

Post · 1 min
Post
May 11, 2026

RealityKit scenes that behave in short tests can degrade in long sessions — rising memory, thermal throttling, or process termination often surface after sustained use

RealityKit scenes that behave in short tests can degrade in long sessions — rising memory, thermal throttling, or process termination often surface after sustained use...

Post · 1 min
Post
Apr 23, 2026

Converting free-text intent slots to `AppIntent` often pushes parsing errors from QA into production — misrouted intents, misclassifications, and new support cases can appear quickly

Converting free-text intent slots to AppIntent often pushes parsing errors from QA into production — misrouted intents, misclassifications, and new support cases can a...

Post · 1 min
Post
Apr 20, 2026

Silently divergent local build scripts once caused a release failure for me — version your build-time tools and move them out of per-developer shell scripts

Silently divergent local build scripts once caused a release failure for me — version your build-time tools and move them out of per-developer shell scripts. Put g...

Post · 1 min
Post
Apr 16, 2026

High-cardinality ad-hoc logs can bury real latency and causal boundaries — use `OSSignposter` to emit bounded, platform-visible intervals instead

High-cardinality ad-hoc logs can bury real latency and causal boundaries — use OSSignposter to emit bounded, platform-visible intervals instead. Create one OSSignp...

Post · 1 min
Post
Apr 13, 2026

Implicit environment values can hide costly dependencies — multiple ancestors injecting the same observable can lead to unexpected re-renders and harder debugging

Implicit environment values can hide costly dependencies — multiple ancestors injecting the same observable can lead to unexpected re-renders and harder debugging. Pr...

Post · 1 min
Post
Apr 6, 2026

Shortcuts that “do nothing” usually hide preventable failures: intent resolution misses, missing prompts, or long work killed silently — make them diagnosable, not mysterious

Shortcuts that “do nothing” usually hide preventable failures: intent resolution misses, missing prompts, or long work killed silently — make them diagnosable, not mys...

Post · 1 min
Post
Apr 1, 2026

Memory growth during long sessions often points to an ownership leak, not a rendering bug — catch it with repeatable `Xcode Memory Graph` snapshots and diffs before assuming layout is the culprit

Memory growth during long sessions often points to an ownership leak, not a rendering bug — catch it with repeatable Xcode Memory Graph snapshots and diffs before assu...

Post · 1 min
Post
Mar 31, 2026

Parsing and type‑checking — not linking — is often what makes CI builds stall

Parsing and type‑checking — not linking — is often what makes CI builds stall. Stale or mismatched .swiftmodule files multiply that pain. Prebuild framework module...

Post · 1 min
Post
Mar 31, 2026

Visual regressions at accessibility text sizes keep slipping into releases — clipped labels and truncated cells are often predictable and preventable

Visual regressions at accessibility text sizes keep slipping into releases — clipped labels and truncated cells are often predictable and preventable. Run automated Dy...

Post · 1 min
Post
Mar 30, 2026

Modifiers that capture mutable state can cause UI surprises under navigation and `List` reuse — treat them as small library contracts, not syntactic sugar

Modifiers that capture mutable state can cause UI surprises under navigation and List reuse — treat them as small library contracts, not syntactic sugar. Define Vi...

Post · 1 min
Post
Mar 29, 2026

Ad‑hoc frame math sprinkled through view bodies breeds flaky, non‑deterministic layout

Ad‑hoc frame math sprinkled through view bodies breeds flaky, non‑deterministic layout. Pull spatial rules into focused Layout types to get deterministic sizing and ea...

Post · 1 min
Post
Mar 27, 2026

A tiny change to `body` or to state ownership can raise per-frame CPU on lower-end devices and turn a calm rollout into an urgent rollback

A tiny change to body or to state ownership can raise per-frame CPU on lower-end devices and turn a calm rollout into an urgent rollback. Profile on representative ph...

Post · 1 min
Post
Mar 22, 2026

Converting globals to explicit DI often surfaces production-only failures: blank screens, duplicated network calls, or stale `ObservableObject` state that don't crash but lengthen incident time

Converting globals to explicit DI often surfaces production-only failures: blank screens, duplicated network calls, or stale ObservableObject state that don’t crash bu...

Post · 1 min
Post
Mar 21, 2026

Converting completion-handler telemetry to async/await can change cancellation and lifecycle semantics — and that can increase the risk of leaking data or leaving on-disk batches after consent changes

Converting completion-handler telemetry to async/await can change cancellation and lifecycle semantics — and that can increase the risk of leaking data or leaving on-d...

Post · 1 min
Post
Mar 16, 2026

If your codebase still uses URLSession completion handlers, moving to Swift async/await can simplify call sites — but it also changes how cancellation, error propagation, and observability are handled

If your codebase still uses URLSession completion handlers, moving to Swift async/await can simplify call sites — but it also changes how cancellation, error propagati...

Post · 1 min
Post
Mar 16, 2026

Stop treating migration from Combine to async/await as a mechanical find‑and‑replace — it’s a different execution model that affects timing, cancellation, and demand semantics

Stop treating migration from Combine to async/await as a mechanical find‑and‑replace — it’s a different execution model that affects timing, cancellation, and demand s...

Post · 1 min
Post
Mar 14, 2026

A tangled web of push/pop calls and segues can slow teams down — but you can migrate to state‑driven navigation incrementally without a big rewrite

A tangled web of push/pop calls and segues can slow teams down — but you can migrate to state‑driven navigation incrementally without a big rewrite. Here’s a practical...

Post · 1 min
Post