为什么我的Swift闭包没有按照预期时机执行?
问题成因
你遇到的是iOS开发中非常典型的异步回调执行时序问题:
observeSingleEvent是Firebase提供的异步网络请求接口,你传入的闭包不会立刻执行,系统会先把请求发出去,然后立刻继续执行闭包后面的同步代码- 所有同步执行的for循环代码会先跑完,等网络请求陆续返回结果后,才会依次调用你传入的闭包,这就是为什么你会看到闭包在整个for循环结束后才批量执行的现象
- 你当前通过UserDefaults中转数据的逻辑完全不适用异步场景,请求还没返回的时候你去读本地存储的值自然是空的
解决方案
你可以把需要在拿到数据后执行的逻辑,直接放到闭包内部执行,就可以保证时序正确:
for id in myCircles { ref.child("\(id)").observeSingleEvent(of: .value, with: { snapshot in let value = snapshot.value as? NSDictionary let circleName = value?["name"] as? String ?? "" let circleCategory = value?["category"] as? String ?? "" let circleID = value?["id"] as? String ?? "" // 直接在回调里执行后续逻辑,不需要通过UserDefaults中转 self.addCircle(circleName: circleName, circleID: circleID, circleCategory: circleCategory) // 如果确实需要本地缓存,也放在这里执行 self.defaults.setValue([circleName, circleID, circleCategory], forKey: "newestCircle"+"\(id)") }) { error in print("请求失败: \(error.localizedDescription)") } }
如果你需要等所有id的请求都返回后再统一执行后续操作,可以使用GCD的DispatchGroup来管理多个异步任务的时序:
let group = DispatchGroup() for id in myCircles { group.enter() ref.child("\(id)").observeSingleEvent(of: .value, with: { snapshot in defer { group.leave() } let value = snapshot.value as? NSDictionary let circleName = value?["name"] as? String ?? "" let circleCategory = value?["category"] as? String ?? "" let circleID = value?["id"] as? String ?? "" self.addCircle(circleName: circleName, circleID: circleID, circleCategory: circleCategory) self.defaults.setValue([circleName, circleID, circleCategory], forKey: "newestCircle"+"\(id)") }) { error in group.leave() print("请求失败: \(error.localizedDescription)") } } // 所有请求完成后会执行这里的代码 group.notify(queue: .main) { print("所有圈子数据加载完成") // 这里可以放需要等全部加载完再执行的逻辑,比如刷新UI }
内容的提问来源于stack exchange,提问作者Swifter
相关产品推荐
相关产品推荐

