Swift & Firebase:Observe函数执行后调用方法的技术问询
如何确保在Observe函数完成后更新TableViewController?
我正在开发一款聊天App,希望在Observe函数执行完成后更新TableViewController。我的代码如下:
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) Api.Message.observeStaticUserDiscussion(toId: self.user!.id!) { (message, messageId, currentId) in if message.notViewed! && currentId != message.fromId { Api.Message.updateMessageStatus(withMessage: messageId, value: false) } } // 需在此Observe函数执行后调用 self.delegate?.updateMenuMessage() }
当前self.delegate?.updateMenuMessage()无法确保在Observe逻辑完成后执行,如何调整实现需求?
这问题我做聊天App的时候也碰到过,核心原因就是observeStaticUserDiscussion里的闭包是异步执行的——外面的updateMenuMessage()会直接先跑,完全等不及闭包里的逻辑处理完。给你几个实用的调整方案:
方案一:直接把更新方法移到闭包内部
如果你的observeStaticUserDiscussion是单次回调(比如只是获取历史消息,不会持续监听新消息),那最简单的办法就是把updateMenuMessage()挪到闭包里面,这样肯定能保证在Observe的逻辑执行完成后再触发更新:
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) Api.Message.observeStaticUserDiscussion(toId: self.user!.id!) { (message, messageId, currentId) in if message.notViewed! && currentId != message.fromId { Api.Message.updateMessageStatus(withMessage: messageId, value: false) } // 闭包逻辑执行完毕后再调用更新,确保在主线程操作UI DispatchQueue.main.async { self.delegate?.updateMenuMessage() } } }
这里加DispatchQueue.main.async是因为很多异步回调会在后台线程触发,而UI更新必须在主线程执行,避免崩溃或UI不刷新的问题。
方案二:用DispatchGroup跟踪异步任务(适合多任务场景)
如果observeStaticUserDiscussion内部有多个异步操作,或者你需要等待所有相关的异步逻辑都完成再更新,那可以用DispatchGroup来管理任务状态:
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) let taskGroup = DispatchGroup() taskGroup.enter() Api.Message.observeStaticUserDiscussion(toId: self.user!.id!) { (message, messageId, currentId) in defer { taskGroup.leave() } // 确保不管逻辑走哪条分支,都会标记任务完成 if message.notViewed! && currentId != message.fromId { Api.Message.updateMessageStatus(withMessage: messageId, value: false) } } // 等所有任务都完成后,在主线程执行UI更新 taskGroup.notify(queue: .main) { self.delegate?.updateMenuMessage() } }
这里的defer关键字很关键,它能保证不管闭包里的代码有没有进入if判断,都会执行taskGroup.leave(),避免出现任务组一直等待的死锁情况。
方案三:区分Observe的回调类型
首先得明确observeStaticUserDiscussion的实际行为:
- 如果是单次获取数据:方案一就完全够用;
- 如果是持续监听新消息(比如类似实时数据库的监听,会多次触发闭包):那你可能需要在第一次回调时执行一次更新,之后每次有新消息再按需刷新,或者加个布尔标记控制只执行一次更新逻辑。
举个持续监听场景的例子:
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) var isFirstCallback = true Api.Message.observeStaticUserDiscussion(toId: self.user!.id!) { (message, messageId, currentId) in if message.notViewed! && currentId != message.fromId { Api.Message.updateMessageStatus(withMessage: messageId, value: false) } // 只在第一次回调时执行更新 if isFirstCallback { DispatchQueue.main.async { self.delegate?.updateMenuMessage() isFirstCallback = false } } } }
内容的提问来源于stack exchange,提问作者KevinB
相关产品推荐
相关产品推荐

