使用UserDefaults同步iOS与WatchOS数据的相关问题咨询
问题根因
你当前使用的UserDefaults.standard仅作用于当前应用的独立沙盒存储空间,iOS应用与WatchOS应用是两个独立的应用实体,默认沙盒完全隔离,因此两端存储的数据互不连通。
另外你现存代码还有逻辑问题:自定义类型[UserClass]无法直接存入UserDefaults,你已经实现了编解码方法,但代码中didSet和init的逻辑还是直接调用set(_:forKey:)和object(forKey:),会导致自定义类型存储失败,后续需要同步替换为编解码逻辑。
解决方案
下面提供两种常用的跨端同步方案,可根据需求选择:
方案1:App Groups 共享UserDefaults(适合小体量、非强实时需求的数据)
该方案通过苹果提供的App Groups能力让同一开发团队下的多个应用共享同一块存储空间,实现数据互通:
- 打开Xcode,分别选中iOS端和WatchOS端的Target,进入「Signing & Capabilities」标签页,点击「+Capability」添加App Groups能力,两端添加完全相同的Group标识,格式为
group.你的自定义标识,例如group.com.yourteam.classschedule - 替换代码中所有的
UserDefaults.standard为共享Group的UserDefaults实例,参考修改:
import Foundation import Combine class UserSettings: ObservableObject { // 初始化共享UserDefaults,注意suiteName要和你配置的App Groups标识完全一致 private let sharedDefaults = UserDefaults(suiteName: "group.com.yourteam.classschedule")! @Published var mon: [UserClass] { didSet { encodeClass(classes: mon, key: "mon") } } @Published var tue: [UserClass] { didSet { encodeClass(classes: tue, key: "tue") } } @Published var wed: [UserClass] { didSet { encodeClass(classes: wed, key: "wed") } } @Published var thu: [UserClass] { didSet { encodeClass(classes: thu, key: "thu") } } @Published var fri: [UserClass] { didSet { encodeClass(classes: fri, key: "fri") } } @Published var homeworks: [String] { didSet { sharedDefaults.set(homeworks, forKey: "homeworks") } } @Published var lastSet: String { didSet { sharedDefaults.set(lastSet, forKey: "lastSet") } } init() { self.mon = decodeClass(key: "mon") self.tue = decodeClass(key: "tue") self.wed = decodeClass(key: "wed") self.thu = decodeClass(key: "thu") self.fri = decodeClass(key: "fri") self.homeworks = sharedDefaults.object(forKey: "homeworks") as? [String] ?? [] self.lastSet = sharedDefaults.object(forKey: "lastSet") as? String ?? "" print("homeworks \(homeworks)") } // 你原有编解码方法内部的UserDefaults也要替换为sharedDefaults func encodeClass(classes: [UserClass], key: String) { do { let encoder = JSONEncoder() let data = try encoder.encode(classes) sharedDefaults.set(data, forKey: key) } catch { print("Unable to Encode Array of Notes (\(error))") } } func decodeClass(key: String) -> [UserClass] { var classes: [UserClass] = [] if let data = sharedDefaults.data(forKey: key) { do { let decoder = JSONDecoder() classes = try decoder.decode([UserClass].self, from: data) } catch { print("Unable to Decode Notes (\(error))") } } return classes } } struct UserClass: Hashable, Codable { let start: String let end: String let name: String }
- 注意:该方案的同步是由系统调度的,存在一定延迟,无法做到实时同步。
方案2:WatchConnectivity 框架同步(适合强实时、双向同步需求)
如果需要两端数据实时同步,可使用苹果官方的WatchConnectivity框架实现端到端数据传输:
- 两端都导入
WatchConnectivity框架,在UserSettings中初始化并激活WCSession,遵守WCSessionDelegate协议 - 任意一端数据更新时,调用
updateApplicationContext(_:)方法将最新数据同步给对端 - 对端收到数据更新回调后,刷新本地存储和UI即可
注意事项
- 两端的
UserClass结构必须完全一致,否则会出现编解码失败问题 - 若后续数据量增大,不推荐继续使用UserDefaults存储,建议替换为Core Data搭配App Groups,或者CloudKit实现多设备同步
内容的提问来源于stack exchange,提问作者Luck_Duracell
相关产品推荐
相关产品推荐

