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

带异步闭包的for循环致Segue传数组为空崩溃的解决问询

兄弟,我太懂这种异步操作没同步好就跳转的崩溃了!你猜的没错,核心问题就是循环里的网络请求是异步执行的——循环跑完的瞬间,大部分请求可能还在后台处理,这时候你直接触发Segue,数组自然是空的,新控制器拿到nil可不就崩溃了嘛。

下面给你两种靠谱的解决方案,按需选就行:

解决方案:同步异步操作后再执行Segue

方法一:传统GCD DispatchGroup(兼容所有Swift版本)

用DispatchGroup来跟踪所有异步请求的完成状态,等全部请求结束后再跳转:

// 先定义要传递的数组
var resultArray: [String] = []
// 创建一个调度组,用来跟踪异步任务
let taskGroup = DispatchGroup()

// 遍历你的数据源
for dataItem in yourDataSourceArray {
    // 每次循环前,告诉组:我要开始一个任务了
    taskGroup.enter()
    
    // 你的异步网络请求(这里假设你有个带回调的请求方法)
    yourNetworkRequestMethod(for: dataItem) { [weak self] responseString in
        // 用defer确保不管请求成功/失败,都告诉组任务完成了
        defer { taskGroup.leave() }
        
        guard let self = self, let string = responseString else { return }
        // 把结果追加到数组
        self.resultArray.append(string)
    }
}

// 所有任务都完成后,在主线程执行Segue
taskGroup.notify(queue: .main) { [weak self] in
    guard let self = self else { return }
    // 这里触发Segue,把数组作为sender传过去
    self.performSegue(withIdentifier: "YourSegueIdentifier", sender: self.resultArray)
}

关键细节:

  • enter()和leave()必须成对出现,不然组会一直等待,永远不会触发notify
  • 用defer包裹leave(),确保即使请求失败(比如网络错误),也不会让组卡住
  • 一定要在主线程执行performSegue,因为UI操作必须在主线程

方法二:Swift 5.5+ Async/Await(更简洁推荐)

如果你用的是Swift 5.5及以上版本,Async/Await会让代码更清爽,不用手动管理组:

首先把你的回调式网络请求改成Async/Await版本:

// 封装原有的回调请求为async函数
func fetchDataAsync(for item: YourDataType) async throws -> String {
    return try await withCheckedThrowingContinuation { continuation in
        yourNetworkRequestMethod(for: item) { result in
            if let string = result {
                continuation.resume(returning: string)
            } else {
                continuation.resume(throwing: NetworkError.invalidResponse)
            }
        }
    }
}

// 自定义错误类型(可选,根据你的需求定义)
enum NetworkError: Error {
    case invalidResponse
}

然后用Task来执行异步循环,等全部完成后跳转:

Task {
    var resultArray: [String] = []
    
    for dataItem in yourDataSourceArray {
        do {
            // 等待当前请求完成,再执行下一次循环
            let responseString = try await fetchDataAsync(for: dataItem)
            resultArray.append(responseString)
        } catch {
            // 处理请求错误,比如打印日志或者跳过当前项
            print("Failed to fetch data for item: \(dataItem), error: \(error)")
        }
    }
    
    // 所有请求完成后,回到主线程执行Segue
    await MainActor.run {
        self.performSegue(withIdentifier: "YourSegueIdentifier", sender: resultArray)
    }
}

最后:在目标控制器正确接收数据

别忘了在prepare(for:sender:)里安全地接收数组,避免nil崩溃:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "YourSegueIdentifier",
       let destinationVC = segue.destination as? YourTargetViewController,
       let receivedArray = sender as? [String] {
        // 把数组赋值给目标控制器的属性
        destinationVC.dataArray = receivedArray
    }
}

额外提醒:

  • 用[weak self]避免循环引用,防止内存泄漏
  • 如果请求数量多,可以考虑用并发循环(比如TaskGroup的async let)来提高效率,但要注意线程安全(数组追加要加锁或者用线程安全的容器)

内容的提问来源于stack exchange,提问作者Žan Fras

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 08:07:55