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

iOS中DispatchGroup notify提前触发:多线程任务未完成即收通知

问题根源分析

你的代码中DispatchGroup.notify()触发过早的核心原因是notify的设置时机错误:

  • 在CompleteState初始化方法里,你立刻调用了dispatch.notify(),但此时所有继承自BaseClass的子类还未创建,dispatch.enter()一次都没执行过,DispatchGroup的待完成任务计数(pending count)为0。
  • 根据GCD规则,当notify被添加到当前计数为0的DispatchGroup时,它的回调会被立刻异步触发,完全不会等待后续的enter()调用和任务执行。
  • 后续创建子类时调用的enter()和任务结束后的leave(),无法触发之前设置的notify回调——因为notify是一次性监听,只会响应它被添加时的状态变化。
修复方案

方案1:延迟设置notify到所有子类初始化完成后

修改CompleteState,将notify的设置从初始化方法中移出,改为单独方法,等所有子类创建完成(所有enter()调用完毕)后再执行:

class CompleteState {
    let userId: String
    let dispatch = DispatchGroup()
    
    init(userId: String) {
        self.userId = userId
        // 移除初始化时的notify调用
    }
    
    // 添加单独方法用于设置完成通知
    func setupCompletionNotification() {
        dispatch.notify(queue: DispatchQueue.main) {
            print("Finish load all data")
        }
    }
}

修改RunAll的初始化逻辑,在创建完所有子类后调用notify设置方法:

public class RunAll {
    let completeState: CompleteState
    let classArray: [BaseClass]
    
    public init(userId: String) {
        self.completeState = CompleteState(userId: userId)
        classArray = [ExampleClass1(completeState: completeState),
                      ExampleClass2(completeState: completeState),
                      ExampleClass3(completeState: completeState),
                      ExampleClass4(completeState: completeState),
                      ExampleClass5(completeState: completeState),
                      ExampleClass6(completeState: completeState),
                      ExampleClass7(completeState: completeState),
                      ExampleClass8(completeState: completeState),
                      ExampleClass9(completeState: completeState)]
        
        // 所有子类初始化完成(所有enter()已调用)后,再设置notify
        completeState.setupCompletionNotification()
        startClasses()
    }
    
    private func startClasses() {
        for foo in classArray {
            foo.start()
        }
    }
}

额外注意事项

  • 必须保证每个enter()对应一个leave():子类代码中leave()在异步任务末尾调用是合理的,但要注意如果任务中出现异常、提前返回,也要确保leave()被执行,避免DispatchGroup永远处于等待状态。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 21:20:28