iOS中DispatchQueue.main.async的正确用法:仅UI还是全逻辑?
关于iOS中DispatchQueue.main.async的正确使用与能耗分析
嘿,这个问题问得特别实用,刚好戳中了iOS开发里线程调度的关键细节!咱们一步步拆解:
一、核心原则:哪些代码必须放主队列?
只有UI相关操作(比如更新tableView、控制activityIndicator、修改UI控件属性等)和访问/修改UIKit框架类实例的代码,必须在主队列执行——因为UIKit是线程不安全的,非主队列操作UI会导致不可预料的崩溃或界面异常。
而像数据处理、数组增删、业务逻辑判断、打印日志这类非UI逻辑,完全可以留在后台线程执行,这样能避免占用主队列资源,让UI保持流畅。
二、两种实现的对比分析
1. 「仅UI操作放主队列」的实现(示例一)
这种做法是更规范、更高效的:
worldMessagesFunctions.delete(wmId: cell.worldMessageId) { response in if let response = response { if response.type == 1 { // 非UI逻辑:后台线程处理数组删除 if let index = WorldMessagesStore.shared.worldMessages.index(where: { $0.id! == cell.worldMessageId }) { WorldMessagesStore.shared.worldMessages.remove(at: index) // 仅UI操作丢去主队列执行 DispatchQueue.main.async { self.tableView.beginUpdates() self.tableView.deleteRows(at: [IndexPath(row: index, section: 0)], with: .automatic) self.tableView.endUpdates() } } print("Okay") } } else { print("Error") } // UI操作丢去主队列 DispatchQueue.main.async { activityIndicator.stopAnimating() activityIndicator.removeFromSuperview() } }
- 优点:把数组查找、删除这类计算型逻辑留在后台,主队列只处理必须的UI更新,减轻主线程负担,避免UI卡顿。
- 注意点:如果
WorldMessagesStore.shared.worldMessages是多线程共享的资源,要额外做线程安全处理(比如加锁、用线程安全的数组容器),防止数据竞争。
2. 「全部逻辑放主队列」的实现(示例二)
这种做法虽然不会导致UI崩溃,但效率很低:
worldMessagesFunctions.delete(wmId: cell.worldMessageId) { response in DispatchQueue.main.async { if let response = response { if response.type == 1 { if let index = WorldMessagesStore.shared.worldMessages.index(where: { $0.id! == cell.worldMessageId }) { WorldMessagesStore.shared.worldMessages.remove(at: index) self.tableView.beginUpdates() self.tableView.deleteRows(at: [IndexPath(row: index, section: 0)], with: .automatic) self.tableView.endUpdates() } print("Okay") } } else { print("Error") } activityIndicator.stopAnimating() activityIndicator.removeFromSuperview() } }
- 问题:主队列是串行队列,本来可以在后台并行处理的数组查找、业务判断,现在都挤到主队列里执行,会占用主线程的时间片,可能导致UI响应变慢(比如滑动tableView卡顿)。
三、能耗对比
第一种实现的能耗更低:
- 后台线程可以利用CPU的多核资源并行处理非UI逻辑,主队列只处理轻量的UI更新,系统的线程调度更高效,不会让主队列长期处于繁忙状态。
- 如果把所有逻辑都塞主队列,主队列忙的时候,其他后台线程可能处于闲置状态,CPU的多核资源没得到充分利用,反而会增加不必要的调度开销,导致能耗上升。
内容的提问来源于stack exchange,提问作者Kárpáti András
相关产品推荐
相关产品推荐

