SwiftUI中结合UserDefaults与ObservableObject的最佳使用方式
适配UserDefaults与ObservableObject的实现方案
问题根源有两点:
- 第一个实现方案没有在类初始化时加载UserDefaults中已存储的缓存数据,且set方法存在变量名错误,导致应用重启后数据丢失
- 第二个实现方案没有用
@Published修饰用户数据属性,数据修改后无法触发视图更新通知
下面是可直接使用的完整实现,同时满足实时更新视图、自动同步UserDefaults的需求:
import SwiftUI // 首先确保你的User模型符合Codable协议 struct User: Codable { var first_name: String var last_name: String var email: String } class SessionData : ObservableObject { // @Published修饰保证修改时通知视图刷新 @Published var loggedInUser: User { didSet { do { let encodedData = try JSONEncoder().encode(loggedInUser) UserDefaults.standard.set(encodedData, forKey: "User") } catch { print("存储用户数据失败: \(error)") } } } static let shared = SessionData() private init() { // 初始化时优先读取UserDefaults中已存储的用户数据 if let savedUserData = UserDefaults.standard.data(forKey: "User") { do { loggedInUser = try JSONDecoder().decode(User.self, from: savedUserData) return } catch { print("解析用户数据失败: \(error)") } } // 没有缓存数据时使用默认空值 loggedInUser = User(first_name: "", last_name: "", email: "") } }
如果你习惯用Combine框架实现,也可以替换成对应写法,逻辑完全一致:
import SwiftUI import Combine class SessionData : ObservableObject { @Published var loggedInUser: User static let shared = SessionData() private var userUpdateObserver: AnyCancellable? private init() { // 初始化读取缓存逻辑和上面一致 if let savedUserData = UserDefaults.standard.data(forKey: "User") { do { loggedInUser = try JSONDecoder().decode(User.self, from: savedUserData) } catch { print("解析用户数据失败: \(error)") loggedInUser = User(first_name: "", last_name: "", email: "") } } else { loggedInUser = User(first_name: "", last_name: "", email: "") } // 监听属性变化自动同步到UserDefaults userUpdateObserver = $loggedInUser .sink(receiveValue: { newUser in do { let encodedData = try JSONEncoder().encode(newUser) UserDefaults.standard.set(encodedData, forKey: "User") } catch { print("存储用户数据失败: \(error)") } }) } }
视图调用方式
原有视图代码无需修改,直接修改属性就会自动同步存储并刷新界面:
struct ProfileView: View { @ObservedObject var sessionData: SessionData = SessionData.shared var body: some View { VStack{ Text(sessionData.loggedInUser.first_name) // 测试修改按钮 Button("修改用户名") { sessionData.loggedInUser.first_name = "新用户名" } } } }
内容的提问来源于stack exchange,提问作者A Akrm
相关产品推荐
相关产品推荐

