在ViewModel中将UserDefaults属性配置为@Published属性的实现方法
解决方案
首先明确两个核心问题:
@Published只能修饰存储属性,不能用于计算属性,你之前的写法不符合语法规则- UserDefaults 的变更不会自动触发 SwiftUI 视图更新,需要手动监听并同步数据
步骤1:优化 UserDefaults 扩展
简化原有的扩展,用 self 替代 UserDefaults.standard(扩展内部的 self 就是当前 UserDefaults 实例,更通用):
extension UserDefaults { var ratedProducts: [Product] { get { guard let data = self.data(forKey: "ratedProducts") else { return [] } return try? PropertyListDecoder().decode([Product].self, from: data) ?? [] } set { self.set(try? PropertyListEncoder().encode(newValue), forKey: "ratedProducts") } } }
注意:
Product必须遵循Codable协议,否则 PropertyList 编解码会失败
步骤2:实现 ViewModel
在 ViewModel 中创建 @Published 存储属性,通过监听 UserDefaults 的变更通知同步数据,同时提供更新方法保证双向同步:
import Combine import SwiftUI class ProductViewModel: ObservableObject { // 用@Published修饰存储属性,触发视图更新 @Published var ratedProducts: [Product] // 存储订阅对象,防止被提前销毁 private var cancellables = Set<AnyCancellable>() init() { // 初始化时从UserDefaults加载初始数据 ratedProducts = UserDefaults.standard.ratedProducts // 监听UserDefaults变更通知,同步更新ViewModel属性 NotificationCenter.default.publisher(for: UserDefaults.didChangeNotification) .receive(on: DispatchQueue.main) // 确保在主线程更新UI相关数据 .sink { [weak self] _ in self?.ratedProducts = UserDefaults.standard.ratedProducts } .store(in: &cancellables) } // 添加评分商品的方法,同时更新UserDefaults和ViewModel func addRatedProduct(_ product: Product) { var currentProducts = UserDefaults.standard.ratedProducts currentProducts.append(product) // 更新UserDefaults,会触发通知进而同步ratedProducts UserDefaults.standard.ratedProducts = currentProducts // 可选:直接更新本地属性,比通知同步更即时 // self.ratedProducts = currentProducts } }
步骤3:在视图中使用
在 SwiftUI 视图中通过 @StateObject 或 @ObservedObject 引用 ViewModel,当 ratedProducts 更新时,进度条会自动刷新:
struct ProgressView: View { @StateObject private var viewModel = ProductViewModel() var body: some View { // 示例:根据ratedProducts数量更新进度条 SwiftUI.ProgressView(value: Double(viewModel.ratedProducts.count), total: 10) Button("添加评分商品") { let testProduct = Product(id: UUID(), name: "测试商品") viewModel.addRatedProduct(testProduct) } } }
内容的提问来源于stack exchange,提问作者mike22
相关产品推荐
相关产品推荐

