URLSession在循环中失效求助:单次调用正常循环调用异常
解决循环调用
getSMAPrices失效的问题 我之前帮朋友排查过类似的URLSession循环调用问题,结合你描述的「单次正常、循环失效」的情况,大概率是这几个核心原因导致的,咱们一步步来解决:
1. 先排查API调用频率限制(最常见原因)
Alpha Vantage的免费API有严格的调用限制:每分钟最多5次请求,每日最多500次。循环里连续发起请求时,几乎瞬间就会触发限流,服务器直接返回429 Too Many Requests错误,但你的函数可能没处理这种错误,导致看起来像是「失效」。
解决方案:给请求之间添加固定延迟,或者用队列控制并发数:
// 更优雅的异步延迟方式(避免阻塞主线程) let symbolsArray = ["AAPL", "MSFT", "GOOG"] for (index, symbol) in symbolsArray.enumerated() { DispatchQueue.global().asyncAfter(deadline: .now() + Double(index) * 13) { self.getSMAPrices(symbol: symbol) } }
2. 检查异步闭包的变量捕获问题
如果你的getSMAPrices函数里用了URLSession的dataTask(with:completionHandler:),循环中可能存在闭包错误捕获循环变量的问题(老版本Swift容易出现),导致所有请求都用了最后一个symbol的值。
解决方案:在循环内显式捕获当前迭代的symbol,或者将其赋值给临时变量:
for symbol in symbolsArray { let currentSymbol = symbol // 临时变量,确保闭包捕获正确的值 getSMAPrices(symbol: currentSymbol) } // 或者在函数内的闭包中显式捕获symbol func getSMAPrices(symbol: String) { let urlString = "https://www.alphavantage.co/query?function=SMA&symbol=\(symbol)&interval=daily&time_period=9&series_type=close&apikey=KPLI12AW8JDXM77Y" guard let url = URL(string: urlString) else { return } URLSession.shared.dataTask(with: url) { [symbol] data, response, error in // 显式捕获symbol,避免变量引用问题 if let error = error { print("请求\(symbol)失败:\(error.localizedDescription)") return } // 后续JSON解析逻辑 }.resume() }
3. 控制URLSession的并发数
默认的URLSession.shared对同一主机的并发连接数有限制(通常是4-8个),循环发起大量请求会导致后续请求被阻塞,直到前面的请求完成。
解决方案:自定义URLSession配置,调整最大并发数:
// 自定义URLSession,限制同一主机同时3个请求 let config = URLSessionConfiguration.default config.httpMaximumConnectionsPerHost = 3 let customSession = URLSession(configuration: config) // 在getSMAPrices里使用这个自定义session func getSMAPrices(symbol: String) { let urlString = "https://www.alphavantage.co/query?function=SMA&symbol=\(symbol)&interval=daily&time_period=9&series_type=close&apikey=KPLI12AW8JDXM77Y" guard let url = URL(string: urlString) else { return } customSession.dataTask(with: url) { data, response, error in // 处理逻辑 }.resume() }
4. 完善错误处理,定位问题根源
你的原始函数可能没有处理请求失败的情况,导致循环中某个请求出错后,你无法得知具体原因。一定要在dataTask的completionHandler里处理error和异常响应:
func getSMAPrices(symbol: String) { let urlString = "https://www.alphavantage.co/query?function=SMA&symbol=\(symbol)&interval=daily&time_period=9&series_type=close&apikey=KPLI12AW8JDXM77Y" guard let url = URL(string: urlString) else { print("无效URL:\(urlString)") return } URLSession.shared.dataTask(with: url) { data, response, error in // 先处理错误 if let error = error { print("获取\(symbol)的SMA数据失败:\(error.localizedDescription)") return } // 再检查响应状态码 guard let httpResponse = response as? HTTPURLResponse, (200...299).contains(httpResponse.statusCode) else { print("请求\(symbol)返回异常状态码:\((response as? HTTPURLResponse)?.statusCode ?? -1)") return } // 后续解析JSON的逻辑 }.resume() }
按照上面的步骤排查,基本就能解决循环调用失效的问题了。
内容的提问来源于stack exchange,提问作者Gareth Loot
相关产品推荐
相关产品推荐

