Mobile (iOS)
Mobile delivery is shaped by OS versions, review, permissions, and background limits. This page focuses on Apple platforms and Swift (personal and product work). Android appears when dual-platform is required—often shared logic via KMP while UI stays native per platform.
Platform constraints
| Constraint | Impact |
|---|---|
| App lifecycle | Short background; state restoration, scenes |
| Permissions | Camera, location, notifications—timing and usage strings |
| Distribution | App Store review, signing, TestFlight |
| Device matrix | Screens, Dynamic Island, accessibility, performance tiers |
SwiftUI structure (default)
| Layer | Role |
|---|---|
| View | Declarative UI; keep body side-effect free |
| Model | @Observable / value-type state |
| Services | Network, persistence, system APIs behind protocols |
Navigation: NavigationStack with type-safe routes; deep links via a single onOpenURL path.
Concurrency: UI on @MainActor; heavy work in Task; respect Sendable across actors.
Preview-first: #Preview with mock services for complex views to cut device churn.
Alignment with layering
| Clean role | Swift placement |
|---|---|
| Domain | Pure Swift types; no UIKit/SwiftUI imports |
| Use cases | async services coordinating repositories |
| Adapters | URLSession, SwiftData/Core Data, Keychain |
| Presentation | Thin SwiftUI views + view models |
Flow: unidirectional—user event → use case → state snapshot → view. Views should not call SDKs directly.
See layering and boundaries.
Persistence choices
| Option | When |
|---|---|
| UserDefaults / Keychain | Settings, tokens (secrets in Keychain only) |
| SwiftData / Core Data | Structured offline data, queries |
| Files / CloudKit | Large blobs, multi-device sync (plan conflicts) |
Ship schema migrations with tests; run simulator UI matrices in CI.
Network and offline
- Shared client defaults: timeouts, retries, cancellable
Task - Lists: skeletons + pagination; retryable errors
- Idempotent writes with client ids server-side
Release checklist
| Step | Action |
|---|---|
| Versions | Marketing version + monotonic build |
| Signing | Automatic or CI certs—no keys in git |
| Privacy | Nutrition labels match implementation and strings |
| Testing | TestFlight → phased release |
| Monitoring | Crashes (MetricKit/third-party), key funnels |
Pair with Git workflow: tags trigger archive/upload jobs.
Quality and accessibility
- Dynamic Type, VoiceOver labels, adequate hit targets
- Avoid gesture-only critical paths; provide visible controls
- Profile with Instruments for main-thread hangs and excess SwiftUI body work