WatchOS Complication读取共享UserDefaults为nil问题求助
问题:Watch Complication无法读取App Group共享的UserDefaults数据
已实现iPhone通过WCSession的ApplicationContext将数据写入共享App Group的UserDefaults,Watch主应用可以正常读取这些数据,但Watch Complication读取同一App Group的UserDefaults时,所有值都返回nil。已确认Complication所在的Watch Extension已开启对应App Group权限,也尝试过重新添加App Group、创建新组,问题依旧。
iPhone端接收并写入共享UserDefaults的代码
func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String : Any]) { let defaults = UserDefaults(suiteName: K.appGroupID) if let value1 = applicationContext["lat"] as? Double { defaults?.setValue(value1, forKey: "lat") } if let value2 = applicationContext["lng"] as? Double { defaults?.setValue(value2, forKey: "lng") } }
Complication端读取代码(返回nil)
func sunsetTime() -> String { let formatter = DateFormatter() formatter.timeStyle = .short formatter.timeZone = .current let defaultLoad = UserDefaults.init(suiteName: K.appGroupID) if defaultLoad!.bool(forKey: "timeFormat") == true { // 此处读取值为nil // ... 后续逻辑 } // ... 返回结果 }
解决步骤
1. 确认Complication Extension的App Groups配置完全正确
- 打开Xcode,选中Complication对应的Extension target,进入Signing & Capabilities标签页
- 确认App Groups已添加,且Group ID和Watch主应用、iPhone应用完全一致(格式如
group.com.yourcompany.yourapp) - 检查Extension的
Info.plist中是否存在com.apple.security.application-groups键,且值包含目标Group ID,若缺失需手动添加
2. 写入UserDefaults时强制同步
Watch主应用写入共享数据后,调用synchronize()确保数据立即持久化到共享容器,避免Complication读取到缓存的空数据:
func session(_ session: WCSession, didReceiveApplicationContext applicationContext: [String : Any]) { guard let defaults = UserDefaults(suiteName: K.appGroupID) else { return } if let value1 = applicationContext["lat"] as? Double { defaults.set(value1, forKey: "lat") } if let value2 = applicationContext["lng"] as? Double { defaults.set(value2, forKey: "lng") } defaults.synchronize() // 强制同步到共享容器 }
3. 修复Complication中的读取逻辑
避免强制解包UserDefaults实例,同时为读取操作设置默认值,防止nil问题:
func sunsetTime() -> String { let formatter = DateFormatter() formatter.timeStyle = .short formatter.timeZone = .current guard let defaultLoad = UserDefaults(suiteName: K.appGroupID) else { print("无法初始化共享UserDefaults") return "N/A" } // 读取时传入默认值,避免nil判断异常 let is24HourFormat = defaultLoad.bool(forKey: "timeFormat") if is24HourFormat { // ... 后续逻辑 } // ... 返回结果 }
4. 给Complication添加数据请求 fallback 方案
Complication可能在Watch主应用未启动时运行,此时可以通过WCSession主动向主应用请求数据:
// 在Complication控制器中实现数据请求逻辑 if WCSession.isSupported() { let session = WCSession.default session.delegate = self session.activate() session.sendMessage(["requestSync": true], replyHandler: { replyData in guard let defaults = UserDefaults(suiteName: K.appGroupID) else { return } // 将主应用返回的数据写入共享容器 if let lat = replyData["lat"] as? Double { defaults.set(lat, forKey: "lat") } if let lng = replyData["lng"] as? Double { defaults.set(lng, forKey: "lng") } defaults.synchronize() }, errorHandler: { error in print("请求主应用数据失败:\(error.localizedDescription)") }) }
同时在Watch主应用的WCSessionDelegate中处理该请求:
func session(_ session: WCSession, didReceiveMessage message: [String : Any], replyHandler: @escaping ([String : Any]) -> Void) { if message["requestSync"] != nil { guard let defaults = UserDefaults(suiteName: K.appGroupID) else { replyHandler([:]) return } // 返回当前共享容器中的数据 let reply = [ "lat": defaults.double(forKey: "lat"), "lng": defaults.double(forKey: "lng"), "timeFormat": defaults.bool(forKey: "timeFormat") ] replyHandler(reply) } }
5. 清理环境重新部署
- 删除iPhone和Watch设备上的应用
- 执行
Product > Clean Build Folder清理Xcode缓存 - 重新构建并部署到设备,确保所有target的签名和Capabilities配置完全同步
内容的提问来源于stack exchange,提问作者Mike B
相关产品推荐
相关产品推荐

