When people build iOS and watchOS apps together, they usually start fast and copy code between targets. It works for a week, then every bug fix has to be done twice. Two weeks later, it feels like you are carrying two apps that look similar but behave differently.

Shared logic should stay in one place while each platform keeps a thin presentation layer.

Step 1: Move business language into shared types

Start by defining a shared model that both platforms can understand. Keep it boring and explicit.

struct SessionSummary: Equatable {
    let minutesToday: Int
    let currentStreak: Int
    let lastUpdatedAt: Date
}

This is your shared language. No UI code yet. No platform code yet.

Step 2: Hide data access behind a protocol

If both apps talk directly to storage or network code, you will duplicate error handling immediately.

protocol SessionStore {
    func loadSummary() async throws -> SessionSummary
    func logSession(minutes: Int) async throws
}

Now both iOS and watchOS can depend on the same interface.

Step 3: Build one view model for both platforms

Centralize behavior in one view model so both platforms stay consistent.

@MainActor
final class SessionViewModel: ObservableObject {
    @Published private(set) var title = "Loading..."
    @Published private(set) var isBusy = false
    @Published private(set) var errorMessage: String?

    private let store: SessionStore

    init(store: SessionStore) {
        self.store = store
    }

    func refresh() async {
        isBusy = true
        defer { isBusy = false }

        do {
            let summary = try await store.loadSummary()
            title = "\(summary.minutesToday) min today | streak \(summary.currentStreak)"
            errorMessage = nil
        } catch {
            errorMessage = "Could not load session summary."
        }
    }
}

At this point, your behavior is centralized. That is the hardest and most valuable part.

Preview: first 50% is visible. Unlock to read the full article.
To view this content, you must be a member of CodeWithWilliamJiamin's Patreon at $1 or more
Already a qualifying Patreon member? Refresh to access this content.