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
相关产品推荐
相关产品推荐

