Swift中sensMessage函数无法串行执行的问题排查与修复
问题分析
你当前的代码没实现预期的串行效果,核心原因是:
- 串行队列
serialQueue里的async任务仅负责触发网络请求,而网络请求本身是异步执行的。当队列内的任务调用完self.sessionManager.request()后,这个任务就已执行完毕,串行队列会立刻调度下一个任务,导致所有"Start"日志一次性输出,完全没等上一个请求的回调完成就启动了下一个请求。
修复方案
要实现真正的串行执行(前一个请求回调触发后再启动下一个),需要让串行队列中的任务等待网络请求的回调完成后再结束,以下提供两种可行方案:
方案一:使用DispatchSemaphore阻塞等待
private let serialQueue = DispatchQueue(label: "com.yourapp.messageQueue") let sessionManager = Session(configuration: configuration, rootQueue: serialQueue, interceptor: self) func sendMessage(message: Message, completion: @escaping (Result) -> Void) { serialQueue.async { [weak self] in guard let self = self else { return } print("Start async queue method: \(message.objectID)") // 自定义前置逻辑 // SOME LOGIC // 创建初始值为0的信号量,用于阻塞当前队列任务 let semaphore = DispatchSemaphore(value: 0) self.sessionManager.request() .response(queue: .global()) { response in // 回调队列不能用serialQueue,否则会因队列线程阻塞导致死锁 print("Finish async queue method: \(message.objectID)") semaphore.signal() // 信号量+1,唤醒等待的线程 // 建议切回主线程执行completion,避免UI操作异常 DispatchQueue.main.async { completion(.success) } } semaphore.wait() // 信号量-1,当前线程阻塞,直到收到signal信号 } }
方案二:任务队列串行调度(无阻塞更优雅)
通过维护一个任务列表,每次仅执行列表中的第一个任务,完成后自动启动下一个,避免线程阻塞:
private let serialQueue = DispatchQueue(label: "com.yourapp.messageQueue") private var pendingMessages: [(Message, (Result) -> Void)] = [] let sessionManager = Session(configuration: configuration, rootQueue: serialQueue, interceptor: self) func sendMessage(message: Message, completion: @escaping (Result) -> Void) { serialQueue.async { [weak self] in guard let self = self else { return } // 将任务加入待执行队列 self.pendingMessages.append((message, completion)) // 只有当队列中只有当前任务时,才启动执行(避免重复触发) guard self.pendingMessages.count == 1 else { return } self.processNextMessage() } } private func processNextMessage() { guard !pendingMessages.isEmpty else { return } let (message, completion) = pendingMessages.removeFirst() print("Start async queue method: \(message.objectID)") // 自定义前置逻辑 // SOME LOGIC self.sessionManager.request() .response(queue: .global()) { response in print("Finish async queue method: \(message.objectID)") DispatchQueue.main.async { completion(.success) } // 回到串行队列,启动下一个任务 self.serialQueue.async { self.processNextMessage() } } }
内容的提问来源于stack exchange,提问作者YosiFZ
相关产品推荐
相关产品推荐

