Skip to content

Architecture and Lifecycle

sonmbol edited this page Jul 28, 2026 · 1 revision

Architecture and Lifecycle

Kotlin StateFlow
    ├── synchronous current value ──→ SwiftUI body
    └── SKIE AsyncSequence ─────────→ shared observation hub
                                         ↓
                                  dependency invalidation

Kotlin remains the only business-state store. Swift stores revision cells, dependency keys, cancellation handles, and wrapper lifetime state.

Dependency behavior

On Observation-capable Apple platforms:

  • $model.field registers a lazy field dependency.
  • An emission for that field updates its revision and the global revision.
  • Unrelated allocated field cells are unchanged.
  • Direct access through model registers a global dependency.
  • A callback with no known field invalidates globally.

Earlier supported platforms use ObservableObject.objectWillChange, preserving correct global invalidation.

Collection sharing

A static macro observation plan uses a weak per-model registry. Wrappers for the same model lease one hub and do not create duplicate StateFlow collectors. The last listener releases the hub and cancels its collectors.

Explicit wrapper adapters define observation locally and should not be assumed to share that static plan.

Coalescing

The default .coalesced policy unions changed dependencies within one main-actor turn and flushes each dependency once. .immediate delivers every accepted emission.

Rebinding and cancellation

When an observed wrapper receives another model:

  1. Pending invalidation work is cancelled.
  2. The previous observation lease is cancelled.
  3. A generation token advances.
  4. Existing dependencies invalidate once for the replacement.
  5. Late emissions from the previous model are rejected.

Task, Combine, callback, and NativeFlow adapters all terminate through the same idempotent cancellation abstraction.

ARC and Kotlin GC

Observation callbacks capture Swift stores weakly. Owning wrappers retain the Kotlin model for their SwiftUI identity; observed and environment wrappers do not claim disposal authority. A shared hub must disappear after its last lease so it cannot retain a Kotlin model across the ARC/GC boundary.

Clone this wiki locally