Files
InvestmentTrackerApp/Shared/WatchSnapshotCache.swift
T
alexandrev-tibco 464fbb2bad App de Apple Watch + 3 complicaciones (build 88) #48
App de watchOS de solo consulta: resumen de cartera (total, cambio del
mes y mayores posiciones), objetivos con su progreso y estado del
check-in con la racha. Toda la edición sigue en el iPhone.

Complicaciones (accessoryCircular / Rectangular / Inline / Corner):
valor total de la cartera, progreso del objetivo más cercano a cumplirse
y racha + estado del check-in.

Datos: los App Groups no se comparten entre iOS y watchOS, así que el
reloj no puede leer el store de CoreData que lee el widget de iOS. En su
lugar, WatchSyncService construye un WatchPortfolioSnapshot ligero y lo
envía como application context de WatchConnectivity, enganchado a
CoreDataStack.refreshWidgetData() — el mismo punto que refresca el widget
de iOS, así que cualquier repositorio que toque datos refresca el reloj.
WatchDataStore lo cachea en el App Group del watch (WatchSnapshotCache) y
recarga las timelines; la extensión de complicaciones solo lee ese caché.

Proyecto: dos targets nuevos (watchOS app + widget extension) con grupos
sincronizados de Xcode 16; Shared/ pertenece a la app de watch y se
comparte con la app de iOS y el widget mediante exception sets, el mismo
mecanismo que ya usaba el widget de iOS para el modelo de CoreData.
Scheme compartido PortfolioJournalWatch. Localización propia por target
en los 7 idiomas.

Verificado: compilan los tres targets, la app de watch queda embebida en
Watch/ con la extensión en PlugIns/, y en el par de simuladores
iPhone 17 Pro Max + Apple Watch Series 11 el reloj recibe y muestra el
snapshot enviado por el iPhone. 10 tests nuevos del payload.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YcDn5ccuRFV83q7xWWokBT
2026-09-13 22:05:31 +02:00

29 lines
1.1 KiB
Swift

import Foundation
/// On-watch cache of the last snapshot received from the iPhone.
///
/// The watch app writes it; the complication extension reads it. They are
/// separate processes, so the App Group container is what lets them share
/// with a fallback to the process defaults so the app still shows data even if
/// the App Group entitlement is not in place yet.
enum WatchSnapshotCache {
private static var sharedDefaults: UserDefaults? {
UserDefaults(suiteName: WatchPortfolioSnapshot.appGroupIdentifier)
}
static func save(_ snapshot: WatchPortfolioSnapshot) {
guard let data = snapshot.encoded() else { return }
let key = WatchPortfolioSnapshot.payloadKey
sharedDefaults?.set(data, forKey: key)
UserDefaults.standard.set(data, forKey: key)
}
static func load() -> WatchPortfolioSnapshot? {
let key = WatchPortfolioSnapshot.payloadKey
let data = sharedDefaults?.data(forKey: key) ?? UserDefaults.standard.data(forKey: key)
guard let data else { return nil }
return WatchPortfolioSnapshot.decoded(from: data)
}
}