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
相关产品推荐
相关产品推荐

