ars*_*ium 0 cocoa objective-c ios
我有三种方法,其中两种同时运行.第三种方法只有在第一种和第二种方法共同完成工作时才能启动.竞争对手的第一种或第二种方法可以先完成工作.
- (void)method1 {
//DO Long Work
isMethod1Complete = YES;
[self method3];
}
- (void)method2 {
//DO Long Work
isMethod2Complete = YES;
[self method3];
}
- (void)method3 {
if (isMethod1Complete && isMethod2Complete) {
//DO Work once
}
}
Run Code Online (Sandbox Code Playgroud)
应始终调用方法3一次.但问题是有一种情况是method1和method2同时完成了工作,而method3被调用了两次.告诉我如何在iOS的目标c中解决这个问题?
更新:一个具体的例子,我有两个服务,当他们完成工作时调用代理.
- (void)method1Handler {
isMethod1Complete = YES;
[self method3];
}
- (void)method2Handler {
isMethod1Complete = YES;
[self method3];
}
Run Code Online (Sandbox Code Playgroud)
如何在没有块的情况下解决这个问题 对于街区而言,Rob的榜样是最好的.
你说:
我有三种方法,其中两种同时运行.
这意味着它们必须是异步的或在后台队列上运行(否则它们无法同时运行).
所以,我们的想法是你应该给他们两个完成处理程序(完成后会调用它们):
- (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
}
Run Code Online (Sandbox Code Playgroud)
在上面的示例中,我添加dispatch_async了对后台队列的显式调用,以确保两个长任务异步运行.但是如果代码已经在做异步(例如网络请求),那么您可能不需要这些dispatch_async调用,只需将completion()调用放在您已经使用的任何API提供的完成处理程序中.但是,如果没有关于什么method1和method2正在做什么的更多信息,我不能更具体.
不过,设置该放在一边,一旦你method1和method2拥有自己完成处理程序,您可以使用dispatch_group_notify来识别当所有的应该做什么dispatch_group_enter电话由其相应的平衡dispatch_group_leave呼叫:
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];
});
Run Code Online (Sandbox Code Playgroud)
在后续评论中,您提到您没有使用基于完成块的API,而是使用基于委托协议的API.您有几个选项,例如:
您可以使用相同的上述闭包模式,但只需将完成处理程序保存为块属性,例如:
例如,定义块属性:
@property (nonatomic, copy, nullable) void (^completionOne)(void);
@property (nonatomic, copy, nullable) void (^completionTwo)(void);
Run Code Online (Sandbox Code Playgroud)
然后,你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;
}
Run Code Online (Sandbox Code Playgroud)
然后,委托协议完成API将调用已保存的块属性(并可能将它们重置nil为释放与这些块关联的内存).
然后,您可以使用上面的原始答案中显示的调度组通知流程.
或者,您可以单独使用调度组,而不是使用块.例如,定义调度组属性:
@property (nonatomic, strong, nullable) dispatch_group_t group;
Run Code Online (Sandbox Code Playgroud)
然后,您创建您的组并开始您的两个任务:
self.group = dispatch_group_create();
[self method1];
[self method2];
dispatch_group_notify(self.group, dispatch_get_main_queue(), ^{
[self method3];
});
Run Code Online (Sandbox Code Playgroud)
然后,这两种方法然后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");
}
Run Code Online (Sandbox Code Playgroud)就个人而言,我通常倾向于第一个选项(这样,调度组的东西包含在一个方法中),但这两种方法都有效.
| 归档时间: |
|
| 查看次数: |
101 次 |
| 最近记录: |