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

SwiftUI中@Published变量userData未更新视图,Firestore异步数据如何触发重绘?

解决方案

核心问题根因

当前问题来自两个错误逻辑:

  1. getUserData 是异步方法,Firestore的getDocuments回调会在网络请求完成后才触发,你直接返回的userData是请求发起前的空数组,外层的赋值操作毫无意义
  2. 对遵循ObservableObject的引用类型FirebaseLogic使用了@Binding修饰,@Binding只用于监听值类型变化,不会响应ObservableObject的@Published更新通知

第一步:修改FirebaseLogic代码

移除getUserData无意义的返回值,确保userData更新在主线程触发(保证UI刷新正常):

class FirebaseLogic: ObservableObject {
    @Published var userData = [UserData]()
    
    // 改为无返回值,内部异步更新@Published变量即可
    func getUserData(uid: String) {
        let db = Firestore.firestore()
        // 清空旧数据
        userData = [UserData]()
        guard let currentUser = Auth.auth().currentUser?.uid else { return }
        
        db.collection("UserData").document(currentUser).collection("Data").getDocuments { [weak self] snapshot, error in
            guard let self = self, let snapshot = snapshot, error == nil else {
                return
            }
            print("Number of documents fb logic get user data: \(snapshot.documents.count)")
            
            // 转换数据
            let userObjects = snapshot.documents.compactMap { doc -> UserData? in
                let documentData = doc.data()
                // 此处保留你原来的UserData转换逻辑
                return userObject
            }
            
            // 显式在主线程更新@Published变量,确保UI收到通知
            DispatchQueue.main.async {
                self.userData = userObjects
            }
        }
    }
}

第二步:修改StatsView代码

  1. 将@Binding改为@ObservedObject来监听ObservableObject的更新
  2. 移除onAppear里无意义的赋值和同步转换逻辑,添加userData变化监听,自动触发数据转换
struct StatsView: View {
    let ID: String
    @EnvironmentObject var statsController: StatsDataController
    @State var reports: [Report] = []
    // 改为@ObservedObject监听ObservableObject的变化
    @ObservedObject var fbLogic: FirebaseLogic
    // 补全你原来的selection、originalReports变量定义
    @State private var selection = 0
    @State private var originalReports: [Report] = []
    
    var body: some View {
        BarGraphView(selection: $selection, reports: $reports, originalReports: $originalReports)
            .environmentObject(statsController)
            .onAppear {
                // 只触发数据拉取,不需要接收返回值
                fbLogic.getUserData(uid: ID)
            }
            // 监听userData的变化,自动执行转换
            .onChange(of: fbLogic.userData) { newUserData in
                self.reports = statsController.convertToReports(users: newUserData)
                self.originalReports = self.reports // 按需给originalReports赋值
                print("fblogic data ", newUserData, " ", ID)
            }
    }
}

兼容iOS13以下版本的替代方案

如果需要支持iOS13,没有onChange modifier,可以用onReceive监听@Published变量的发布者:

// 替换onChange块即可
.onReceive(fbLogic.$userData) { newUserData in
    self.reports = statsController.convertToReports(users: newUserData)
    self.originalReports = self.reports
    print("fblogic data ", newUserData, " ", ID)
}

修改完成后,只要fbLogic.userData被异步更新,就会自动触发转换逻辑,重绘BarGraphView。

内容的提问来源于stack exchange,提问作者AAH

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.15 01:27:04