SwiftUI中Firestore数据无法显示问题求助
问题分析与解决方案
你的代码中存在两个核心问题导致列表无法显示,同时还有一处潜在的崩溃风险,以下是具体修复方案:
1. 核心问题:@Published属性更新未在主队列执行
Firestore的回调方法运行在后台队列,而SwiftUI的@Published属性必须在主队列更新才能触发UI刷新。你在错误分支中直接赋值self.devices,没有切换到主队列,这会导致UI无法感知数据变化。
2. 次要问题:DeviceType枚举无法直接从Firestore字符串转换
Firestore中存储的type字段是字符串类型,但你直接用data["type"] as? DeviceType转换会返回nil(Swift枚举默认不支持这种隐式转换),虽然这不会直接导致列表为空,但会破坏数据完整性。
3. 潜在风险:强制解包authModel.user
authModel.user!.uid的强制解包会在用户未登录时导致崩溃,需要替换为安全的可选绑定。
具体修复代码
修复FirestoreManager类
import Foundation import Firebase class FirestoreManager: ObservableObject { @Published var devices: [Device] = [] func fetchAllDevicesForUser(uid: String) { let db = Firestore.firestore() db.collection("users/" + uid + "/devices").getDocuments { (querySnapshot, error) in guard let documents = querySnapshot?.documents else { print("No docs") // 错误分支也切换到主队列更新数据 DispatchQueue.main.async { self.devices = [Device(name: "You currently don't have any devices.", id: "", type: .none)] } return } DispatchQueue.main.async { self.devices = documents.map { queryDocumentSnapshot -> Device in let data = queryDocumentSnapshot.data() let name = data["name"] as? String ?? "" // 通过rawValue将Firestore字符串转换为DeviceType枚举 let typeRaw = data["type"] as? String ?? "none" let type = DeviceType(rawValue: typeRaw) ?? .none print(name) return Device(name: name, id: queryDocumentSnapshot.documentID, type: type) } } } } }
修复DeviceType枚举
让枚举支持字符串原始值,才能和Firestore的存储格式匹配:
import Foundation // 添加String raw type,支持从字符串转换 enum DeviceType: String { case drone case none } struct Device: Identifiable { let name: String let id: String let type: DeviceType }
修复HomeView的可选值处理
import SwiftUI struct HomeView: View { @EnvironmentObject private var authModel: AuthViewModel @StateObject var firestoreManager = FirestoreManager() var body: some View { ScrollView { Text("Welcome,") .font(.title) Text(authModel.user?.displayName ?? "User") .font(.largeTitle) .bold() Button("Add Device") { } .buttonStyle(.borderedProminent) Text("Devices") .font(.title2) .bold() List(firestoreManager.devices) { device in Text(device.name) } .onAppear() { // 安全获取用户ID,避免强制解包崩溃 guard let uid = authModel.user?.uid else { print("User not authenticated") return } self.firestoreManager.fetchAllDevicesForUser(uid: uid) } } .navigationTitle("Home") } } struct HomeView_Previews: PreviewProvider { static var previews: some View { HomeView() .environmentObject(AuthViewModel()) // 预览时提供环境对象 } }
额外验证步骤
- 确认Firestore控制台中
users/{你的用户ID}/devices路径下存在文档,且name字段有有效值 - 确认
AuthViewModel的user属性已正确初始化,并通过environmentObject传递到HomeView
内容的提问来源于stack exchange,提问作者Jacob Miller
相关产品推荐
相关产品推荐

