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

如何在批量异步requestItem请求全部完成后执行后续代码?

如何等待所有异步请求完成后执行后续代码?

首先得纠正一个小问题:你原来的代码里let item = requestItem(id)写法不对哦——异步函数不会直接返回结果,通常是通过闭包回调或者async/await来传递结果的,直接赋值拿不到正确的异步返回值。

下面给你两种常用的解决方案,适配不同的Swift版本:


方案一:用DispatchGroup(兼容Swift 5.5之前的版本)

DispatchGroup是苹果提供的用来跟踪一组异步任务的工具,每个任务开始时“进入”group,完成时“离开”group,当所有任务都离开后,就能触发后续逻辑。

假设你的requestItem是基于闭包的异步函数(比如定义为:func requestItem(_ id: Int, completion: @escaping (Item?) -> Void)),代码可以这么写:

var IDs = [Int]()
var items = [Item]()
let taskGroup = DispatchGroup()
// 可选:如果需要保证items数组的线程安全,用一个串行队列
let itemsQueue = DispatchQueue(label: "com.yourapp.itemsQueue")

for id in IDs {
    taskGroup.enter() // 标记一个任务开始
    requestItem(id) { [weak self] fetchedItem in
        defer { taskGroup.leave() } // 无论成功失败,都要离开group,避免死等
        
        guard let item = fetchedItem else {
            print("加载id:\(id)失败")
            return
        }
        
        // 线程安全地更新items数组
        itemsQueue.sync {
            self?.items.append(item)
        }
    }
}

// 所有任务完成后执行后续代码
taskGroup.notify(queue: .main) { [weak self] in
    print("所有Item都加载完成啦!当前items数量:\(self?.items.count ?? 0)")
    // 这里写你的后续逻辑,比如更新UI、处理数据等
}

注意点:

  • 一定要保证每个enter()对应一个leave(),哪怕请求失败也要调用,不然group会一直等待,后续代码永远不会执行。
  • 如果异步回调在后台线程,更新items时要注意线程安全,用串行队列或者锁来避免数据竞争。

方案二:用async/await(Swift 5.5+,iOS 15+/macOS 12+等)

这是Swift现代并发模型推荐的方式,代码更简洁易读,错误处理也更规范。

首先需要你的requestItem是异步函数(比如定义为:func requestItem(_ id: Int) async throws -> Item),然后可以用Task来并发执行所有请求,再等待全部完成:

var IDs = [Int]()

// 封装加载逻辑的异步函数
func loadAllItems() async -> [Item] {
    // 创建一组并发任务
    let tasks = IDs.map { id in
        Task {
            do {
                return try await requestItem(id)
            } catch {
                print("加载id:\(id)失败:\(error)")
                throw error // 也可以返回nil,根据你的需求调整错误处理逻辑
            }
        }
    }
    
    // 等待所有任务完成,收集结果
    var items = [Item]()
    for task in tasks {
        do {
            let item = try await task.value
            items.append(item)
        } catch {
            // 单个任务失败的处理,比如跳过该item
            continue
        }
    }
    return items
}

// 调用方式(必须在异步上下文里,比如Task中)
Task {
    let allLoadedItems = await loadAllItems()
    print("所有Item加载完成,共\(allLoadedItems.count)个")
    // 这里执行后续代码,比如更新UI(如果在主队列的Task,直接操作UI即可)
    // self.items = allLoadedItems
}

优势:

  • 代码结构更线性,不用嵌套多层闭包,可读性更强。
  • 错误处理通过do-catch统一管理,逻辑更清晰。
  • 系统自动处理线程调度,不用手动管理队列和线程安全(只要不在多个Task里同时修改同一个可变变量即可)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:39:34