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

Swift中DataTask的完成处理程序为何始终不执行?

问题原因

在Swift命令行程序中,主线程的RunLoop默认不会持续运行。URLSession.dataTask是异步执行的,当main函数执行完毕后,进程会立即退出,根本没有等待网络任务完成并触发回调。这就是你看不到任何任务相关输出、程序直接显示Finished with exit code 0的原因。

解决方案

下面提供几种可行的修复方式,你可以根据需求选择:

方法1:使用信号量(DispatchSemaphore)阻塞主线程

通过信号量让主线程等待异步任务完成后再退出:

修改main.swift代码:

import Foundation

let urlString = "https://api.edamam.com/api/food-database/v2/parser?app_id=4c38caa6&app_key=kkk&ingr=eggs 4 small"
guard let encodedUrlString = urlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
      let url = URL(string: encodedUrlString) else {
    fatalError("Invalid URL")
}

// 创建信号量,初始值为0
let semaphore = DispatchSemaphore(value: 0)

Requests.makeGet(url: url) { d, e in
    print("Inside closure from main")
    print("Data: \(d ?? Data())")
    print("Error: \(e ?? "No error")")
    // 任务完成,发送信号让主线程继续执行
    semaphore.signal()
}

// 阻塞主线程,等待信号量
semaphore.wait()

方法2:使用RunLoop保持程序运行

让主线程的RunLoop持续运行,直到异步任务完成:

修改main.swift代码:

import Foundation

let urlString = "https://api.edamam.com/api/food-database/v2/parser?app_id=4c38caa6&app_key=kkk&ingr=eggs 4 small"
guard let encodedUrlString = urlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
      let url = URL(string: encodedUrlString) else {
    fatalError("Invalid URL")
}

var shouldKeepRunning = true

Requests.makeGet(url: url) { d, e in
    print("Inside closure from main")
    print("Data: \(d ?? Data())")
    print("Error: \(e ?? "No error")")
    // 任务完成,标记退出RunLoop
    shouldKeepRunning = false
}

// 持续运行RunLoop直到任务完成
while shouldKeepRunning {
    RunLoop.main.run(until: Date().addingTimeInterval(0.1))
}

方法3:使用Async/Await(Swift 5.5+)

如果你的Swift版本支持Async/Await,这种方式代码更简洁易读,也不需要手动管理线程阻塞:

首先更新Requests结构体:

import Foundation

struct Requests {
    static func makeGet(url: URL) async throws -> Data {
        let (data, response) = try await URLSession.shared.data(from: url)
        
        // 可选:检查HTTP响应状态码
        guard let httpResponse = response as? HTTPURLResponse,
              (200...299).contains(httpResponse.statusCode) else {
            throw NSError(domain: "RequestError", code: -1, userInfo: [NSLocalizedDescriptionKey: "Invalid HTTP response"])
        }
        
        return data
    }
}

然后修改main.swift:

import Foundation

// 启动异步任务
Task {
    let urlString = "https://api.edamam.com/api/food-database/v2/parser?app_id=4c38caa6&app_key=kkk&ingr=eggs 4 small"
    guard let encodedUrlString = urlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed),
          let url = URL(string: encodedUrlString) else {
        fatalError("Invalid URL")
    }
    
    do {
        let data = try await Requests.makeGet(url: url)
        print("Received data: \(data)")
    } catch {
        print("Request failed with error: \(error)")
    }
    
    // 任务完成后退出程序
    exit(0)
}

// 保持RunLoop运行,等待异步任务完成
RunLoop.main.run()

内容的提问来源于stack exchange,提问作者Daniel Crompton

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 22:28:16