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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 13:10:25