SwiftUI中@Published变量userData未更新视图,Firestore异步数据如何触发重绘?
解决方案
核心问题根因
当前问题来自两个错误逻辑:
getUserData是异步方法,Firestore的getDocuments回调会在网络请求完成后才触发,你直接返回的userData是请求发起前的空数组,外层的赋值操作毫无意义- 对遵循
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代码
- 将
@Binding改为@ObservedObject来监听ObservableObject的更新 - 移除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
相关产品推荐
相关产品推荐

