Dispatch Group配合网络请求完成块失效问题排查求助
问题:使用Starscream的Session批量请求仅返回第一个ID的结果
你提到用基于Starscream API的session类批量调用接口时,只有第一个ID的结果被打印出来,代码如下:
let myGroup = DispatchGroup() for i in 0 ..< marketIds.count { myGroup.enter() self.session.retrieve(withMethod: MarketKeys.key, withParameters: [MarketKeys.id: marketIds[i]], completion: { (results, error) in print("results \n") print(results!) myGroup.leave() }) } myGroup.notify(queue:.main) { print("Done") }
排查与解决方案
嘿,我来帮你分析下可能的问题点,以及对应的解决办法:
1. 最可能的原因:单个Session实例不支持并发请求
Starscream是WebSocket库,很多基于它封装的session类可能一次只能处理一个请求——当你在循环里连续调用retrieve时,后续的请求可能会覆盖第一个请求的上下文,或者被session内部的逻辑拦截了,导致只有第一个请求能正常完成并触发回调。
解决办法:为每个请求创建独立的Session实例
如果你的session类允许,可以在循环内初始化新的session实例来处理每个请求,确保每个请求都有独立的连接/上下文:
let myGroup = DispatchGroup() for id in marketIds { myGroup.enter() // 初始化新的session实例,适配你的类初始化方式 let requestSession = YourSessionClass() requestSession.retrieve( withMethod: MarketKeys.key, withParameters: [MarketKeys.id: id], completion: { (results, error) in print("results \n") print(results!) myGroup.leave() // 按需清理session实例 } ) } myGroup.notify(queue:.main) { print("Done") }
2. 闭包变量捕获的潜在问题
虽然Swift现在默认会在循环中为每个迭代创建独立的变量引用,但老版本Swift或者某些特殊场景下,闭包可能会捕获到循环变量的同一个引用(不过你说只返回第一个结果,这个可能性相对低,但可以排查)。
解决办法:显式捕获当前迭代的ID
在循环内先把当前ID存到局部变量里,再传给请求,避免捕获问题:
let myGroup = DispatchGroup() for i in 0 ..< marketIds.count { let currentId = marketIds[i] // 显式保存当前迭代的ID myGroup.enter() self.session.retrieve( withMethod: MarketKeys.key, withParameters: [MarketKeys.id: currentId], completion: { (results, error) in print("results \n") print(results!) myGroup.leave() } ) } myGroup.notify(queue:.main) { print("Done") }
3. Session内部的请求串行限制
如果你的session类本身要求请求必须串行执行(比如WebSocket的消息发送需要按顺序),那并行调用retrieve会导致后续请求无法正常触发。
解决办法:用串行队列控制请求顺序
用一个串行队列来逐个发送请求,确保前一个请求完成后再发送下一个:
let requestQueue = DispatchQueue(label: "com.yourapp.market.requests") let myGroup = DispatchGroup() requestQueue.async { for id in marketIds { myGroup.enter() // 如果session需要在主线程调用,就切换到主线程 DispatchQueue.main.async { self.session.retrieve( withMethod: MarketKeys.key, withParameters: [MarketKeys.id: id], completion: { (results, error) in print("results \n") print(results!) myGroup.leave() } ) } // 等待当前请求完成,再进行下一个 myGroup.wait() } // 所有请求完成后通知主线程 myGroup.notify(queue:.main) { print("Done") } }
额外建议:检查Session类的实现
如果以上方法都没用,建议查看你封装的session类中retrieve方法的源码:
- 是否在调用时会取消之前未完成的请求?
- 是否有并发请求的限制逻辑?
- WebSocket连接是否在请求过程中被意外关闭?
内容的提问来源于stack exchange,提问作者Russell Warwick
相关产品推荐
相关产品推荐

