You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:36:24