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

Swift 4中如何等待异步任务执行完成?

解决Firebase异步数据读取的结构体填充问题

没问题,我来帮你搞定这个异步回调的坑!你说得对,Firebase的数据库操作是异步的——你的fetchJSON函数里,ref.observe(.value)的闭包会在数据从服务器返回后才执行,但你现在把self.meals.append(meal)放在了闭包外面,这时候meal的属性还没被赋值,自然是空的。

正确的做法是用回调闭包,把数据准备好后的操作放在回调里执行。

先修改你的fetchJSON函数,给它加一个完成回调参数:

func fetchJSON(key: String, completion: @escaping (Meal?) -> Void) {
    let ref = rootRef.child(key)
    // 如果只需要读取一次数据,推荐用observeSingleEvent,避免重复监听数据变化
    ref.observeSingleEvent(of: .value) { snap in
        // 用可选绑定替代强制解包,避免数据格式不对导致崩溃
        guard let firstMeal = snap.childSnapshot(forPath: "first").value as? String,
              let secondMeal = snap.childSnapshot(forPath: "second").value as? String,
              let thirdMeal = snap.childSnapshot(forPath: "third").value as? String else {
            print("数据缺失或格式不符合预期")
            completion(nil)
            return
        }
        // 数据验证通过,创建并填充Meal实例
        let meal = Meal()
        meal.firstMeal = firstMeal
        meal.secondMeal = secondMeal
        meal.thirdMeal = thirdMeal
        // 通过回调把准备好的meal传递出去
        completion(meal)
    }
}

然后调用这个函数的时候,在回调闭包里处理meal的后续操作:

fetchJSON(key: currentDate) { [weak self] meal in
    guard let self = self, let fetchedMeal = meal else {
        // 处理错误情况:比如数据未获取到,或者self已被释放
        return
    }
    // 此时meal已经被正确赋值,可以放心添加到数组
    self.meals.append(fetchedMeal)
    // 如果需要更新UI,记得切回主线程(Firebase闭包默认在后台线程执行)
    DispatchQueue.main.async {
        // 举个例子:刷新表格视图
        self.tableView.reloadData()
    }
}

几个关键注意点:

  • 避免强制解包:用as?替代as!,如果Firebase返回的数据格式和预期不符,会进入错误分支而不是直接崩溃。
  • 防止循环引用:回调里用[weak self],再通过guard let self = self确保self未被释放,避免内存泄漏。
  • 主线程更新UI:所有UI操作必须在主线程执行,所以如果回调里要更新界面,一定要用DispatchQueue.main.async包裹。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 06:47:50