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

iOS开发:如何在不阻塞主线程时解决GCD异步任务的竞态条件?

问题拆解与解决方案

首先得说,你当前的代码有两个核心问题,导致完全达不到你想要的效果:

  1. 异步任务没等就返回了:DispatchAsync是把任务丢到后台线程异步执行的,所以ShouldPerformSegue会立刻返回初始值false,根本没等后台的耗时操作完成。
  2. 线程安全风险:直接在后台线程修改isAllowed变量,主线程和后台线程同时访问这个变量,很容易出现竞态条件,导致不可预期的结果。

而且ShouldPerformSegue本身是个同步方法——它必须立刻返回结果,没法在这里原地等待异步任务完成(那样会直接阻塞主线程,导致应用冻结,正好是你想避免的情况)。

正确的实现思路

咱们换个思路:先不让系统自动执行segue(返回false),等后台异步任务完成后,再手动触发segue跳转。这样既不会阻塞主线程,又能保证任务完成后再执行跳转,还能彻底避免竞态条件。

修改后的代码

public override bool ShouldPerformSegue(string segueIdentifier, NSObject sender) { 
    // 先阻止系统默认的segue触发
    ActivityIndicator.StartAnimating(); 

    // 把耗时任务丢到后台线程执行
    DispatchQueue.GetGlobalQueue(DispatchQueuePriority.High).DispatchAsync(()=> { 
        // 这里替换成你的实际耗时业务逻辑
        NSThread.SleepFor(2); 

        // 任务完成后必须切回主线程(UI操作和segue触发都要在主线程)
        DispatchQueue.MainQueue.DispatchAsync(()=> {
            ActivityIndicator.StopAnimating(); 
            // 手动触发segue跳转
            PerformSegue(segueIdentifier, sender); 
        }); 
    }); 

    return false; 
}

额外优化:防止重复触发

如果用户快速多次点击触发segue的控件,可能会同时启动多个后台任务,咱们可以加个标记变量来避免这种情况:

// 标记是否有任务在执行,默认是false
private bool _isTaskInProgress = false;

public override bool ShouldPerformSegue(string segueIdentifier, NSObject sender) { 
    // 如果已经有任务在跑,直接返回false,拒绝新的触发
    if (_isTaskInProgress) return false;
    
    _isTaskInProgress = true;
    ActivityIndicator.StartAnimating(); 

    DispatchQueue.GetGlobalQueue(DispatchQueuePriority.High).DispatchAsync(()=> { 
        // 模拟耗时操作
        NSThread.SleepFor(2); 

        DispatchQueue.MainQueue.DispatchAsync(()=> {
            // 任务完成后重置标记
            _isTaskInProgress = false;
            ActivityIndicator.StopAnimating(); 
            PerformSegue(segueIdentifier, sender); 
        }); 
    }); 

    return false; 
}

补充说明

  • 所有UI相关的操作(比如ActivityIndicator的启动/停止)必须在主线程执行,代码里已经处理了这一点;
  • 如果你的异步任务可能失败(比如网络请求出错),可以在主线程的回调里添加错误处理逻辑——比如显示提示弹窗,不触发segue;
  • 不要用NSThread.SleepFor在实际项目里模拟耗时操作哦,这里只是为了演示,实际要替换成真正的业务逻辑(比如网络请求、本地数据处理等)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 10:29:51