等待多个街区完成

Has*_*mad 13 nsoperation nsoperationqueue grand-central-dispatch ios objective-c-blocks

我有这些方法从互联网上检索一些对象信息:

- (void)downloadAppInfo:(void(^)())success
                failure:(void(^)(NSError *error))failure;
- (void)getAvailableHosts:(void(^)())success
                  failure:(void(^)(NSError *error))failure;
- (void)getAvailableServices:(void(^)())success
                     failure:(void(^)(NSError *error))failure;
- (void)getAvailableActions:(void(^)())success
                    failure:(void(^)(NSError *error))failure;
Run Code Online (Sandbox Code Playgroud)

下载的东西存储在对象属性中,这就是成功函数不返回任何内容的原因.

现在,我想要一个像这样的方法:

- (void)syncEverything:(void(^)())success
               failure:(void(^)(NSError *error))failure;
Run Code Online (Sandbox Code Playgroud)

除了调用上面的所有方法之外,它只会在每个方法执行其成功或失败块之后返回.

我怎样才能做到这一点?

提示:我知道级联方法调用彼此成功块会起作用.但是,当后来的实现包括更多方法时,这既不"干净"也不有用.

尝试:

我尝试在a中运行每个调用NSOperation并将其添加NSOperations到a NSOperationQueue后跟"完成操作",这取决于前面的每个操作.

这不行.由于即使在各自的成功/失败块返回之前也认为操作已完成.

我也试过用dispatch_group.但我不清楚我是以正确的方式做到这一点.不幸的是,它没有用.

pka*_*amb 15

从这里的其他答案的评论中得出,以及博客文章使用调度组等待多个Web服务,我得出了以下答案.

此解决方案使用dispatch_group_enterdispatch_group_leave确定每个中间任务何时运行.完成所有任务后,将dispatch_group_notify调用最后一个块.然后,您可以调用完成块,知道所有中间任务都已完成.

dispatch_group_t group = dispatch_group_create();

dispatch_group_enter(group);
[self yourBlockTaskWithCompletion:^(NSString *blockString) {

    // ...

    dispatch_group_leave(group);
}];

dispatch_group_enter(group);
[self yourBlockTaskWithCompletion:^(NSString *blockString) {

    // ...

    dispatch_group_leave(group);
}];

dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),^{

    // All group blocks have now completed

    if (completion) {
        completion();
    }
});
Run Code Online (Sandbox Code Playgroud)

Grand Central Dispatch - 派遣团体

https://developer.apple.com/documentation/dispatch/dispatchgroup

分组块允许聚合同步.您的应用程序可以提交多个块并跟踪它们是否全部完成,即使它们可能在不同的队列上运行.在完成所有指定任务之前无法进行此操作时,此行为很有用.

Xcode片段:

我发现自己使用了Dispatch Groups,我已经将以下代码添加为Xcode片段,以便于插入到我的代码中.

现在我输入DISPATCH_SET并插入以下代码.然后,为每个异步块复制并粘贴enter/ leave.

dispatch_group_t group = dispatch_group_create();

dispatch_group_enter(group);

dispatch_group_leave(group);

dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),^{

});
Run Code Online (Sandbox Code Playgroud)


mic*_*tox 10

你几乎就在那里,问题很可能是那些方法是异步的,所以你需要一个额外的同步步骤.试试以下修复:

for(Appliance *appliance in _mutAppliances) {
  dispatch_group_async(
     group,
     dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
       dispatch_semaphore_t sem = dispatch_semaphore_create( 0 );

       NSLog(@"Block START");

       [appliance downloadAppInfo:^{
          NSLog(@"Block SUCCESS");
            dispatch_semaphore_signal(sem);
       }
       failure:^(NSError *error){
         NSLog(@"Block FAILURE");
         dispatch_semaphore_signal(sem);
       }];

       dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);

       NSLog(@"Block END");
 });

 dispatch_group_notify(
   group,
   dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),^{
     NSLog(@"FINAL block");
     success();
 });
}
Run Code Online (Sandbox Code Playgroud)

  • 我不建议使用dispatch_semaphore_wait()来阻塞线程,而是建议使用dispatch_group_enter()和dispatch_group_leave()为您已经在的同一组"扩展"该组到完成回调,这样一切都是完全异步的. (8认同)
  • 我的意思是将dispatch_group_enter()放在dispatch_semaphore_create()和dispatch_group_leave()的地方,你有dispatch_semaphore_signal()并删除dispatch_sempahore_wait().如果其中一个是可能的,另一个也是可能的. (6认同)