如何正确获取URLSession异步请求返回值用于后续计算存储
问题根因
你遇到的是异步函数同步返回的典型问题:
URLSession.dataTask属于异步执行逻辑,fetchData的completion闭包会在网络请求完成后才触发,执行时机远晚于getGainLossNumber的return操作- 你声明
finalPrice = 0.0后立刻执行了return,此时闭包还没拿到网络返回结果,自然永远返回初始值0
解决方案1:沿用回调模式(兼容旧版Swift)
把getGainLossNumber也改成异步回调的形式,不直接返回值,而是通过completion传递计算结果:
func getGainLossNumber(brand: String, quantity: Int, price: Double, completion: @escaping (Double) -> Void) { APImodel.fetchData(brand: brand) { returnedDouble in let currentPrice = returnedDouble let finalPrice: Double if quantity < 0 { let orderQuantity = quantity * -1 finalPrice = price + (currentPrice * Double(orderQuantity) * 100) } else { finalPrice = price - (currentPrice * Double(quantity) * 100) } completion(finalPrice) } }
调用时通过闭包接收结果即可:
// 调用示例 getGainLossNumber(brand: "目标品牌", quantity: 10, price: 5.0) { finalPrice in // 拿到计算结果后再执行后续操作,比如存CoreData、刷新UI // 注意如果要操作UI需要切回主线程:DispatchQueue.main.async { 你的UI逻辑 } }
解决方案2:使用Swift Concurrency(Swift 5.5+ 推荐)
如果你的项目支持iOS 15+/macOS 12+,可以用async/await改写异步逻辑,避免回调嵌套,写法更直观:
首先改写fetchData为async版本:
func fetchData(brand: String) async throws -> Double { let urlString = "\(quoteUrl)\(brand)" guard let url = URL(string: urlString) else { throw NSError(domain: "InvalidURL", code: -1) } var request = URLRequest(url: url) request.addValue("application/json", forHTTPHeaderField: "Accept") request.addValue("Bearer \(key)", forHTTPHeaderField: "Authorization") let (data, _) = try await URLSession.shared.data(for: request) let decodedData = try JSONDecoder().decode(DataModel.self, from: data) let bid = decodedData.quotes.quote.bid let ask = decodedData.quotes.quote.ask return (bid + ask) / 2 }
对应改写getGainLossNumber:
func getGainLossNumber(brand: String, quantity: Int, price: Double) async throws -> Double { let currentPrice = try await APImodel.fetchData(brand: brand) if quantity < 0 { let orderQuantity = quantity * -1 return price + (currentPrice * Double(orderQuantity) * 100) } else { return price - (currentPrice * Double(quantity) * 100) } }
调用方式:
Task { do { let finalPrice = try await getGainLossNumber(brand: "目标品牌", quantity: 10, price: 5.0) // 拿到结果后处理后续逻辑 } catch { // 处理网络请求、解析等异常 print(error) } }
内容的提问来源于stack exchange,提问作者Mr_Bull3t
相关产品推荐
相关产品推荐

