你说:
我有三个方法,其中两个同时运行。
这意味着它们必须是异步的或在后台队列上运行(否则它们无法同时运行)。
所以,我们的想法是你应该给它们两个完成处理程序(它们完成后将被调用):
- (void)method1WithCompletion:(void(^ _Nonnull)(void))completion {
dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{
//DO Long Work asynchronously
completion();
});
}
- (void)method2WithCompletion:(void(^ _Nonnull)(void))completion {
dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), ^{
//DO Long Work asynchronously
completion();
});
}
- (void)method3 {
// final task
}
在上面的示例中,我向后台队列添加了显式的dispatch_async 调用,以确保两个长任务异步运行。但是,如果代码已经在执行异步操作(例如网络请求),那么您可能不需要这些 dispatch_async 调用,只需将 completion() 调用放在您已经使用的任何 API 提供的完成处理程序中即可。但如果没有更多关于 method1 和 method2 正在做什么的信息,我无法更具体。
但是,撇开这些不谈,一旦您的 method1 和 method2 拥有自己的完成处理程序,您就可以使用 dispatch_group_notify 来确定当所有 dispatch_group_enter 调用都由它们对应的 @ 平衡时应该做什么987654323@电话:
dispatch_group_t group = dispatch_group_create();
dispatch_group_enter(group);
[self method1WithCompletion:^{
dispatch_group_leave(group);
}];
dispatch_group_enter(group);
[self method2WithCompletion:^{
dispatch_group_leave(group);
}];
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
[self method3];
});
在随后的 cmets 中,您提到您使用的不是基于完成块的 API,而是基于委托协议的 API。您有几个选择,例如:
-
您可以使用与上述相同的闭包模式,但只需将完成处理程序保存为块属性,例如:
例如,定义块属性:
@property (nonatomic, copy, nullable) void (^completionOne)(void);
@property (nonatomic, copy, nullable) void (^completionTwo)(void);
然后,您的 method1 和 method2 将保存这些块:
- (void)method1WithCompletion:(void(^ _Nonnull)(void))completion {
self.completionOne = completion;
// start your time consuming asynchronous process
}
// and your completion delegate method can then call the saved closure
// and then remove it
- (void)method1DidComplete {
self.completionOne();
self.completionOne = nil;
}
- (void)method2WithCompletion:(void(^ _Nonnull)(void))completion {
self.completionTwo = completion;
// start second asynchronous process
}
// same as above
- (void)method2DidComplete {
self.completionTwo();
self.completionTwo = nil;
}
然后,委托协议完成 API 将调用保存的块属性(并可能将它们重置为 nil 以释放与这些块关联的内存)。
然后您可以使用上面我原始答案中所示的调度组通知过程。
-
或者,您可以单独使用调度组,而不是使用块。例如定义调度组属性:
@property (nonatomic, strong, nullable) dispatch_group_t group;
然后,你创建你的组并开始你的两个任务:
self.group = dispatch_group_create();
[self method1];
[self method2];
dispatch_group_notify(self.group, dispatch_get_main_queue(), ^{
[self method3];
});
并且,当您启动任务时这两个方法然后是 dispatch_group_enter 和各自的完成处理程序委托方法中的 dispatch_group_leave:
- (void)method1 {
dispatch_group_enter(self.group);
// start first asynchronous process
}
// in your delegate completion method, you "leave" the group
- (void)method1DidComplete {
dispatch_group_leave(self.group);
}
- (void)method2 {
dispatch_group_enter(self.group);
// start second asynchronous process
}
- (void)method2DidComplete {
dispatch_group_leave(self.group);
}
- (void)method3 {
// you might as well remove the group now that you're done with it
self.group = nil;
// final task
NSLog(@"doing three");
}
就个人而言,我通常倾向于第一个选项(这样,调度组的内容包含在一个方法中),但任何一种方法都有效。