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
相关产品推荐
相关产品推荐

