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

Swift Playground如何避免空数组?API请求无法获取邮箱数组问题

问题分析:无法从API异步请求中获取邮箱数组

你的代码核心问题是异步任务的执行时机和同步返回值的矛盾,具体原因如下:

  • URLSession.shared.dataTask是异步执行的,调用getEmailFromAPI后,函数会立刻遍历完所有URL并启动异步任务,然后直接返回空的emails数组——这时候所有异步请求还没完成,自然拿不到数据。
  • 你添加的DispatchQueue.main.async { emails.append(result.data.email) }只是把数组追加操作放到了主线程,但根本问题(函数提前返回空数组)并没有解决,所以结果还是空的。

解决方案1:使用Swift Async/Await(推荐,Swift 5.5+)

将函数改为异步函数,通过async/await等待每个请求完成,确保返回数组时所有请求都已处理完毕:

// MARK: - Response Class
struct Response: Codable {
    let data: DataClass
    let support: Support
}

// MARK: - DataClass
struct DataClass: Codable {
    let id: Int
    let email, firstName, lastName: String
    let avatar: String

    enum CodingKeys: String, CodingKey {
        case id, email
        case firstName = "first_name"
        case lastName = "last_name"
        case avatar
    }
}

// MARK: - Support
struct Support: Codable {
    let url: String
    let text: String
}

let urls = [
    URL(string: "https://reqres.in/api/users/1"),
    URL(string: "https://reqres.in/api/users/3"),
    URL(string: "https://reqres.in/api/users/10")
]

func getEmailFromAPI(urls: [URL?]) async -> [String] {
    var emails: [String] = []
    for url in urls {
        guard let url = url else { continue }
        do {
            let (data, _) = try await URLSession.shared.data(from: url)
            let result = try JSONDecoder().decode(Response.self, from: data)
            emails.append(result.data.email)
        } catch {
            print("请求或解析失败:\(error)")
        }
    }
    return emails
}

// 调用示例(需在异步上下文中执行,比如Task或@MainActor标注的函数)
Task {
    let emails = await getEmailFromAPI(urls: urls)
    print(emails)
}

解决方案2:使用闭包回调(兼容旧版本Swift)

如果项目无法使用Async/Await,可通过闭包传递结果,用DispatchGroup等待所有异步任务完成后再返回:

// 结构体定义保持不变

func getEmailFromAPI(urls: [URL?], completion: @escaping ([String]) -> Void) {
    var emails: [String] = []
    let group = DispatchGroup()
    let semaphore = DispatchSemaphore(value: 1) // 保证数组操作的线程安全

    for url in urls {
        guard let url = url else { continue }
        group.enter()
        URLSession.shared.dataTask(with: url) { data, response, error in
            defer { group.leave() }
            guard let data = data else { return }
            do {
                let result = try JSONDecoder().decode(Response.self, from: data)
                semaphore.wait()
                emails.append(result.data.email)
                semaphore.signal()
            } catch {
                print("请求或解析失败:\(error)")
            }
        }.resume()
    }

    group.notify(queue: .main) {
        completion(emails)
    }
}

// 调用示例
getEmailFromAPI(urls: urls) { emails in
    print(emails)
}

额外注意事项

  • 不要强制解包url!,用guard let url = url else { continue }避免空值崩溃
  • 解析JSON时替换try?为do-catch,方便捕获并排查解析错误
  • 多线程操作数组时,需用信号量或串行队列保证线程安全,避免数据竞争

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 18:50:26