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

Swift数组添加元素问题:Firestore请求后外部函数中数组为空

问题分析与解决方案

问题根源

  • Firestore的getDocuments是异步网络请求,它的回调闭包会在数据请求完成后才执行。你在viewDidLoad里调用itemsList()后立刻执行print(items)和showCatalogVC(),这时候异步请求还没结束,items数组自然是空的。
  • showCatalogVC()方法里错误地重新实例化了一个CatalogVC,这个新实例的items数组初始为空,且没有触发数据请求,所以展示后也看不到内容。

修复方案

1. 确保数据加载完成后再执行后续逻辑

把需要依赖items数组的操作(比如打印、更新UI、跳转页面)放到getDocuments的回调闭包内,或者通过Combine监听@Published属性的变化:

方式一:回调内处理

修改itemsList方法,在数据加载完成后执行后续操作:

func itemsList(){
    database.collection("catalog")
        .getDocuments { (snapshot, error) in
            self.items.removeAll()
            
            if let snapshot {
                for document in snapshot.documents{
                    let docData = document.data()
                    let title: String = docData["title"] as? String ?? ""
                    let imageUrl: String = docData["imageUrl"] as? String ?? ""
                    let description: String = docData["description"] as? String ?? ""
                    let price: Int = docData["price"] as? Int ?? 0
                    
                    let item: Item = Item(title: title, price: price, description: description, imageUrl: imageUrl)
                    
                    self.items.append(item)
                }
                // 数据加载完成后执行后续操作
                print(self.items)
                self.updateCatalogUI() // 更新textView内容
            }
            
            if let error {
                print("获取数据失败:\(error.localizedDescription)")
            }
        }
}

// 新增更新UI的方法
private func updateCatalogUI() {
    let catalogText = items.map { "\($0.title) - ¥\($0.price)\n\($0.description)\n" }.joined()
    textViewCatalog.text = catalogText
}

然后修改viewDidLoad,移除提前执行的操作:

override func viewDidLoad() {
    super.viewDidLoad()
    let settings = FirestoreSettings()
    Firestore.firestore().settings = settings
    itemsList()
}

方式二:用Combine监听@Published变化

因为你使用了@Published属性,可以通过Combine监听数组变化,自动触发后续操作:

import Combine // 需要导入Combine框架

class CatalogVC: UIViewController {
    // ... 其他代码不变
    
    private var cancellables = Set<AnyCancellable>()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        let settings = FirestoreSettings()
        Firestore.firestore().settings = settings
        
        // 监听items的变化,主线程更新UI
        $items
            .receive(on: DispatchQueue.main)
            .sink { [weak self] updatedItems in
                print(updatedItems)
                self?.updateCatalogUI()
            }
            .store(in: &cancellables)
        
        itemsList()
    }
    
    // ... 其他代码不变
}

2. 修复showCatalogVC方法的错误

你当前在CatalogVC内弹出新的CatalogVC逻辑不合理,若要跳转其他页面,可修改为实例化目标VC并传递数据:

private func showProductListVC() {
    let storyboard = UIStoryboard(name: "Main", bundle: nil)
    let productVC = storyboard.instantiateViewController(withIdentifier: "ProductListVC") as! ProductListVC
    productVC.items = self.items // 传递加载好的数组
    self.present(productVC, animated: true, completion: nil)
}

然后在itemsList的回调内调用这个方法,确保数据加载完成后再跳转。

额外优化建议

  • 用Firestore内置解码功能替换手动解析字段,减少出错概率:
struct Item: Codable {
    var title: String
    var price: Int
    var description: String
    var imageUrl: String
}

// 在itemsList中替换手动解析逻辑
if let snapshot {
    for document in snapshot.documents {
        do {
            let item = try document.data(as: Item.self)
            self.items.append(item)
        } catch {
            print("解码失败:\(error.localizedDescription)")
        }
    }
}
  • 完善错误处理,避免数据加载失败时无提示。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 21:50:23