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

SwiftUI应用在Firebase数据加载前崩溃,报数组越界错误求助

解决Firebase异步加载数据导致的数组越界错误

问题根源

你遇到的index out of range错误,核心原因是视图渲染速度快于Firebase异步数据加载:

  • 初始化时DataManager的prompts是空数组
  • addSnapshotListener是异步回调,Firebase返回数据需要时间,但MainView一启动就直接访问prompts[0],空数组取索引0必然崩溃。

解决方法

给你两种可行的修改方案,任选其一即可:

方案1:条件渲染(推荐)

在视图里先判断数组是否有内容,再显示对应文本,避免越界:

struct MainView: View {
    @EnvironmentObject var dataManager: DataManager
    
    var body: some View {
        ScrollView(.vertical) {
            VStack {
                // 先判断数组非空,再取第一个元素
                if let firstPrompt = dataManager.prompts.first {
                    Text(firstPrompt.text)
                        .foregroundColor(.accentColor)
                        .font(.largeTitle)
                        .fontWeight(.semibold)
                } else {
                    // 数据未加载时显示占位文本
                    Text("加载中...")
                        .foregroundColor(.gray)
                }
            }.padding()
            
            Divider()
        }
    }
}

方案2:加载状态占位(更友好)

如果想给用户更直观的加载反馈,可以用ProgressView替代占位文本:

struct MainView: View {
    @EnvironmentObject var dataManager: DataManager
    
    var body: some View {
        ScrollView(.vertical) {
            VStack {
                if !dataManager.prompts.isEmpty {
                    Text(dataManager.prompts[0].text)
                        .foregroundColor(.accentColor)
                        .font(.largeTitle)
                        .fontWeight(.semibold)
                } else {
                    ProgressView() // 加载指示器
                        .padding()
                }
            }.padding()
            
            Divider()
        }
    }
}

额外优化建议

可以给DataManager加个isLoading状态,更精准控制加载UI:

class DataManager: ObservableObject {
    @Published var prompts: [Prompts] = []
    @Published var isLoading = true // 新增加载状态
    private var db = Firestore.firestore()
    
    init() {
        fetchPrompts()
    }
    
    func fetchPrompts() {
        db.collection("prompts").addSnapshotListener { (querySnapshot, error) in
            self.isLoading = false // 回调触发后标记加载完成
            guard let documents = querySnapshot?.documents else {
                print("no documents")
                return
            }

            self.prompts = documents.map { queryDocumentSnapshot -> Prompts in
                let data = queryDocumentSnapshot.data()
                let text = data["promptText"] as? String ?? ""
                let id = data["id"] as? Int ?? 0
                return Prompts(id: id, text: text)
            }
        }
    }
}

然后在MainView里用isLoading判断:

if dataManager.isLoading {
    ProgressView()
} else if let firstPrompt = dataManager.prompts.first {
    Text(firstPrompt.text)
        .foregroundColor(.accentColor)
        .font(.largeTitle)
        .fontWeight(.semibold)
} else {
    Text("暂无数据")
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 18:15:01