Swift中如何等待任务完成后执行主线程及相关错误问题
Swift网络请求异步问题与错误警告处理
一、为什么最后一行print(exchange_value)输出0.0?
URLSession的dataTask是异步执行的,主线程会直接往下走执行最后的print,根本不等网络请求完成。另外你在闭包里重新定义了let exchange_value,这是个局部变量,和外面的全局exchange_value完全无关,就算请求完成也不会修改全局变量的值。
解决方法
方法1:用Swift 5.5+的async/await(最推荐,代码更简洁)
Playground里需要开启异步支持,修改后的代码如下:
import Foundation import PlaygroundSupport PlaygroundPage.current.needsIndefiniteExecution = true // 保持你的结构体定义不变 struct Information: Codable { let success: Bool let query: Query let info: Info let date: String let result: Double } struct Info: Codable { let timestamp: Int let rate: Double } struct Query: Codable { let from, to: String let amount: Int } // 封装异步请求函数 func fetchExchangeRate() async throws -> Double { let url = "https://api.apilayer.com/exchangerates_data/convert?to=AED&from=GBP&amount=1" var request = URLRequest(url: URL(string: url)!, timeoutInterval: Double.infinity) request.httpMethod = "GET" request.addValue("REAL KEY REMOVED HERE", forHTTPHeaderField: "apikey") let (data, _) = try await URLSession.shared.data(for: request) let information = try JSONDecoder().decode(Information.self, from: data) return information.result } // 调用异步函数 Task { do { let exchange_value = try await fetchExchangeRate() print(exchange_value) // 请求完成后才会执行打印 } catch { print("请求错误:\(error)") } PlaygroundPage.current.finishExecution() // 任务结束后终止Playground }
方法2:用信号量(适配老版本Swift)
适合在Playground里用,主线程通过信号量等待异步任务完成(注意不要在APP主线程这么做,会阻塞界面):
import Foundation // 结构体定义不变... let semaphore = DispatchSemaphore(value: 0) var exchange_value: Double = 0.0 let url = "https://api.apilayer.com/exchangerates_data/convert?to=AED&from=GBP&amount=1" var request = URLRequest(url: URL(string: url)!,timeoutInterval: Double.infinity) request.httpMethod = "GET" request.addValue("REAL KEY REMOVED HERE", forHTTPHeaderField: "apikey") let task = URLSession.shared.dataTask(with: request) { data, response, error in defer { semaphore.signal() } // 无论成功失败都发出信号 guard let data = data else { print(String(describing: error)) return } do { let information = try JSONDecoder().decode(Information.self, from: data) exchange_value = information.result // 修改全局变量 } catch let error { print("解码错误:\(error)") } } task.resume() semaphore.wait() // 等待异步任务完成 print(exchange_value) // 现在能拿到正确结果
二、错误警告Immutable value 'error' was never used的原因
你在catch let error里定义了error变量,但只打印了固定字符串"error",完全没用到这个error变量本身。Xcode会提示你:既然这个变量没用,要么把它换成_表示忽略,要么实际使用它(比如打印错误详情)。
修复方式
- 不需要查看错误详情时,直接忽略:
catch { print("请求出错") } - 需要打印错误信息时,使用变量:
catch let error { print("请求错误:\(error.localizedDescription)") }
内容的提问来源于stack exchange,提问作者Kapi
相关产品推荐
相关产品推荐

