多方法并行控制:如何确保method3仅在method1与method2均完成后执行一次
嘿,这个场景我熟!你的现有代码虽然能实现需求,但有两个小瑕疵:一是method3会被两次调用(哪怕只有一次真正执行核心逻辑),二是如果method1和method2在多线程环境下运行,isMethod1Complete、isMethod2Complete这两个变量可能存在线程安全问题。
下面给你几个更优雅的优化方案,按推荐程度排序:
方案1:用GCD Dispatch Group(最推荐,简洁高效)
这是iOS/macOS里处理多任务同步最常用的方式,不需要手动维护状态标记,系统会自动帮我们监听两个任务的完成状态,确保method3只执行一次。
步骤如下:
- 先定义一个
dispatch_group_t属性,用来管理任务组:
@property (nonatomic, strong) dispatch_group_t taskGroup;
- 在合适的地方(比如初始化方法里)创建任务组:
self.taskGroup = dispatch_group_create();
- 修改
method1和method2,把耗时任务加入任务组:
- (void)method1 { // 标记任务进入组 dispatch_group_enter(self.taskGroup); // 把耗时任务放到后台队列执行(如果你的任务已经是异步的,直接在任务结束处调用leave即可) dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 这里写你的耗时任务逻辑 // 任务完成后标记离开组 dispatch_group_leave(self.taskGroup); }); } - (void)method2 { dispatch_group_enter(self.taskGroup); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 这里写你的耗时任务逻辑 dispatch_group_leave(self.taskGroup); }); }
- 设置任务组的通知,当两个任务都完成时自动调用
method3:
// 这里可以指定method3执行的队列,比如主队列(如果需要更新UI) dispatch_group_notify(self.taskGroup, dispatch_get_main_queue(), ^{ [self method3]; });
这样method3只会被调用一次,完全不用关心method1和method2谁先完成。
方案2:改进现有逻辑,加线程安全保护+避免重复调用
如果不想用GCD Group,也可以给你的现有逻辑打补丁,解决线程安全和重复调用的问题:
- 新增一个标记变量和锁:
@property (nonatomic, assign) BOOL isMethod1Complete; @property (nonatomic, assign) BOOL isMethod2Complete; @property (nonatomic, assign) BOOL isMethod3Executed; // 标记method3是否已经执行过 @property (nonatomic, strong) NSRecursiveLock *taskLock; // 用来保证线程安全
- 初始化锁:
self.taskLock = [[NSRecursiveLock alloc] init];
- 修改
method1、method2和拆分method3:
- (void)method1 { // 执行耗时任务 [self.taskLock lock]; self.isMethod1Complete = YES; [self.taskLock unlock]; [self checkAndRunMethod3]; } - (void)method2 { // 执行耗时任务 [self.taskLock lock]; self.isMethod2Complete = YES; [self.taskLock unlock]; [self checkAndRunMethod3]; } // 单独做检查逻辑,避免重复调用 - (void)checkAndRunMethod3 { [self.taskLock lock]; BOOL shouldExecute = self.isMethod1Complete && self.isMethod2Complete && !self.isMethod3Executed; if (shouldExecute) { self.isMethod3Executed = YES; } [self.taskLock unlock]; if (shouldExecute) { [self realMethod3]; } } - (void)realMethod3 { // 这里写原来method3里需要仅执行一次的任务 }
这个方案通过锁解决了多线程下的状态竞争问题,同时用isMethod3Executed确保核心逻辑只执行一次,不会像原来那样method3被调用两次。
方案3:用NSOperation依赖关系
如果你的项目已经在用NSOperation管理任务,那可以通过依赖关系来实现需求:
// 创建操作队列 NSOperationQueue *taskQueue = [[NSOperationQueue alloc] init]; // 封装method1的耗时任务 NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{ // 这里写method1里的耗时任务逻辑 }]; // 封装method2的耗时任务 NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{ // 这里写method2里的耗时任务逻辑 }]; // 封装method3的任务 NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{ [self method3]; }]; // 设置依赖:op3必须等op1和op2都完成才能执行 [op3 addDependency:op1]; [op3 addDependency:op2]; // 添加所有操作到队列 [taskQueue addOperations:@[op1, op2, op3] waitUntilFinished:NO];
这个方案的优势是任务依赖关系清晰,适合复杂任务调度的场景。
总的来说,GCD Dispatch Group是最省心的方案,代码简洁,不需要维护额外的状态变量,还自带线程安全保障。
内容的提问来源于stack exchange,提问作者arsenium
相关产品推荐
相关产品推荐

