You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 23:36:17