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

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()) // 预览时提供环境对象
    }
}

额外验证步骤

  1. 确认Firestore控制台中users/{你的用户ID}/devices路径下存在文档,且name字段有有效值
  2. 确认AuthViewModel的user属性已正确初始化,并通过environmentObject传递到HomeView

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 21:55:04