programming-ios · git:20260510.fe97ca3 · 2026-05-10 · sha256 0654cc928469810e
programming-ios git:20260510.fe97ca3A
Immutable. This exact content is served forever at /api/v1/blob/0654cc928469810e.
--- name: programming-ios title: "iOS Development" description: "iOS architecture with SwiftUI, SwiftData, App Intents, WidgetKit, and modern platform integrations. Auto-activates for iOS projects." license: Apache-2.0 compatibility: "Requires Xcode 16+ and iOS 17+ SDK." capabilities: programming-swift domains: developer rules: - content(ios) - content(iphone) - content(ipad) - content(uikit) - match(iphone.+app|ios.+app|ipad.+app) - file(*.xcodeproj) --- ## Mental model A modern iOS app is SwiftUI views over `@Observable` models, with SwiftData (or a small repository layer) for persistence and App Intents for system-level integration. UIKit is the escape hatch for what SwiftUI can't yet express. Architectural mistakes show up as massive view bodies, scattered singletons, and tight coupling to `UIApplication` — design for testability by isolating side effects behind protocols. ## Architecture - Feature-first organization: each feature owns its views, models, intents, and tests in one folder - Domain logic lives in framework-free Swift modules (a separate SPM target) — the UI imports the domain, not the other way around - Side effects (network, persistence, system services) hide behind protocols injected via `@Environment` or initializer parameters - Avoid singletons except for genuinely process-wide resources (logger, telemetry); inject everything else - Keep `App` and `Scene` definitions thin — they wire dependencies and nothing more ## SwiftUI patterns - `@Observable` model classes for view state; `@Bindable` to create bindings to their properties - `NavigationStack` with typed `NavigationLink(value:)` for type-safe routing; `NavigationPath` for heterogeneous stacks - `NavigationSplitView` for iPad/macOS layouts — collapses to stack on iPhone automatically - `.task` modifier for async work tied to view lifetime — cancels on disappear - `.environment(...)` to inject services down the tree; custom `EnvironmentKey` for app-specific dependencies - View bodies should read like a layout description — push computation into the model ## Data and persistence - SwiftData with `@Model` for new projects — schema is derived from the type, lightweight migrations are automatic - `@Query` in views for filtered, sorted, animated fetches - `ModelContainer` configured at the app entry point; injected via `.modelContainer(...)` - CloudKit sync via SwiftData when cross-device persistence is needed - `#Predicate` macro for type-safe queries; `VersionedSchema` + `SchemaMigrationPlan` for non-trivial migrations - For non-SwiftData persistence, hide Core Data / files / keychain behind a repository protocol ## System integration - App Intents make actions discoverable by Shortcuts, Siri, Spotlight, and Apple Intelligence - `AppEntity` for domain objects the system can reason about; `AppShortcutsProvider` for surfaced shortcuts - Widgets via WidgetKit with `TimelineProvider`; Live Activities via ActivityKit for lock-screen and Dynamic Island - StoreKit 2 (`Product.products(for:)`, `Transaction.currentEntitlements`) — no delegate callbacks, no receipt parsing - `PrivacyInfo.xcprivacy` declares all required-reason API usage — ship with it from day one ## UIKit interop - Wrap UIKit views with `UIViewRepresentable` / `UIViewControllerRepresentable` only when SwiftUI lacks an equivalent - Keep the bridge thin: a single representable per feature, not scattered across views - For UIKit-first apps, embed SwiftUI screens via `UIHostingController` — incremental migration works well ## Concurrency - Adopt Swift 6 strict concurrency — main-thread mistakes become compile errors - `@MainActor` on view models and anything touching UIKit/SwiftUI - Network and persistence on background actors or detached tasks; results cross back via `await` - Cancel structured tasks (`.task`) automatically; for unstructured work, hold `Task` handles and cancel explicitly ## Testing - Swift Testing (`@Test`, `#expect`, `@Suite`) for unit and integration tests - Test the domain target without the app — fast, deterministic, no simulator - `#Preview` doubles as a visual test for layout across states - XCUITest for end-to-end flows; keep them short and focused on critical user paths - Mock system services by injecting the protocol you defined, not by stubbing Apple's classes ## Distribution - TestFlight for internal and external betas; phased rollouts on App Store releases - Stay current with the Privacy Manifest required-reason API list — Apple expands it regularly - Symbolicate crash reports via dSYMs uploaded with each build