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

iOS异步Completion Block未调用:GCD场景下复现代码求助

主队列串行特性导致Completion Block无法执行的问题分析与解决

问题本质

主队列是串行队列,所有提交到主队列的任务会严格按顺序执行,同一时间只能有一个任务在主队列线程上运行。

代码执行流程拆解

  1. viewDidLoad本身在主队列执行,调用dispatch_async(dispatch_get_main_queue(), ...)会把[self runMyCode]这个任务追加到主队列的任务列表末尾。
  2. viewDidLoad执行完成后,主队列开始处理这个追加的任务,进入runMyCode方法。
  3. runMyCode中调用runSomeAsyncAPI,这类异步API的Completion Block通常默认会提交到主队列执行(尤其是涉及UI操作的API)。
  4. 此时主队列的任务队列里,当前正在运行的是runMyCode中的while循环——这个循环不断调用runMode:beforeDate:让RunLoop处理事件,但本质上它一直占用着主队列线程,主队列无法切换到下一个任务(也就是那个未执行的Completion Block)。
  5. 而不使用dispatch_async时,runMyCode直接在viewDidLoad的主队列任务中执行,runSomeAsyncAPI的Completion Block会被插入到当前RunLoop的事件队列中,在while循环的runMode调用过程中被处理,因此能正常触发completed = YES,跳出循环。

解决方法

方案1:用异步回调替代阻塞等待(推荐)

彻底摒弃阻塞式的while循环,改用Completion Block链式处理逻辑:

- (void)runMyCodeWithCompletion:(void(^)(void))completion {
    [self runSomeAsyncAPI:^{
        if (completion) {
            completion();
        }
    }];
}

- (void)viewDidLoad {
    [super viewDidLoad];
    [self runMyCodeWithCompletion:^{
        // 在这里处理异步任务完成后的逻辑
    }];
}

方案2:将阻塞逻辑移到后台队列

如果必须等待异步任务完成,不要在主队列阻塞,切换到全局队列等待,避免占用主队列线程:

- (void)runMyCode {
    dispatch_group_t taskGroup = dispatch_group_create();
    dispatch_group_enter(taskGroup);
    
    [self runSomeAsyncAPI:^{
        dispatch_group_leave(taskGroup);
    }];
    
    // 切换到后台队列等待,不阻塞主队列
    dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{
        dispatch_group_wait(taskGroup, DISPATCH_TIME_FOREVER);
        // 异步任务完成,处理后续逻辑
        // 如果需要更新UI,切回主队列
        dispatch_async(dispatch_get_main_queue(), ^{
            // UI更新操作
        });
    });
}

- (void)viewDidLoad {
    [super viewDidLoad];
    [self runMyCode];
}

关键提示

永远不要在主队列上执行阻塞式操作(比如无限循环、长时间等待),主队列需要保持响应以处理UI渲染、用户交互等核心任务,阻塞主队列不仅会导致其他任务无法执行,还会造成界面卡顿、APP无响应(ANR)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 02:33:33