【问题标题】:Run 3 methods one after each other依次运行 3 种方法
【发布时间】:2015-02-10 11:05:08
【问题描述】:

我需要在调用 api (NSURLSessionDataTask async) 的单独线程中一个接一个地运行 3 个方法。我已经查看了调度组,但这似乎同时运行方法 1 和 2,然后在它们完成时运行方法 3:

dispatch_group_t group = dispatch_group_create();

//METHOD 1
dispatch_group_enter(group);
[self method1WithCompletion:^(BOOL success){
    dispatch_group_leave(group);
}];

//METHOD 2
dispatch_group_enter(group);
[self method2WithCompletion:^(BOOL success){
    dispatch_group_leave(group);
}];

dispatch_group_notify(group,dispatch_get_main_queue(),^{
    //METHOD 3
});

我需要它来运行方法 1,当它完成时运行方法 2,当它完成时,最终运行方法 3(对方法进行排队)。

我知道我可以在每次完成时链接方法以运行下一次,但我认为会有更好的方法来解决这个问题......有什么想法吗?

【问题讨论】:

  • 调用[self method1]有什么问题; [自我方法2]; [自我方法3]; ?
  • @RicardPérezdelCampo 这样做将导致所有 3 个异步任务立即发生。他想在方法1完成后调用方法2,在方法2完成后调用方法3。
  • 这样不行吗? [self method1WithCompletion:^(BOOL success){ [self method2WithCompletion:^(BOOL success){ [self method3WithCompletion:^(BOOL success){ }]; }]; }];
  • 是的,它会,但他在问题中明确表示他不想这样做:)“我知道我可以在每个完成时链接方法以运行下一个但我认为那里会是一个更好的方法”

标签: objective-c xcode grand-central-dispatch nsurlsessiondatatask


【解决方案1】:

你很接近。

dispatch_group_enter 和公司只处理生成它的位,因此 dispatch_group_enters 到 dispatch_group_t 的所有内容都将在调用传递到 dispatch_group_notify 的块之前完成。

所以我们可以在等待任务时好好利用它们。我们可以为每个需要完成的异步任务使用一个组,而不是只有一个组等待每个任务完成:

// You can get a global queue or create your own, it doesn't really matter
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// Create a group for each task you want to wait for
dispatch_group_t group1 = dispatch_group_create();
dispatch_group_t group2 = dispatch_group_create();

// Call your first task on the first group
dispatch_group_enter(group1);
[self method1WithCompletion:^(BOOL success){
    // Task is completed, so signal that it has finished
    dispatch_group_leave(group1);
}];

// Call your 2nd task on the 2nd group
dispatch_group_enter(group2);
// Make the second task wait until group1 has completed before running
dispatch_group_notify(group1, queue, ^{
    // METHOD 2
    [self method2WithCompletion:^(BOOL success){
        // Signal to the group that the task has completed
        dispatch_group_leave(group2);
    }];
});

// Nothing is waiting on the 3rd task, so no need to create a group for it
dispatch_group_notify(group2,dispatch_get_main_queue(),^{
    //METHOD 3
    // Do whatever you need to do in here
});

这里有更多关于Dispatch Queues 以及如何使用它们的信息。

编辑:对不起,我完全改变了我的答案。一旦你留下你的评论,我就觉得你调用的任务是异步的,使用串行dispatch_queue_t 不会有什么不同! (块是串行运行的,但是method2会在method1之后立即运行,而不是等待完成)

【讨论】:

  • 感谢 cjwirth,所以在我的 method1WithCompletion 调用中,这是否仍然适用于串行队列,或者是否也需要调整:NSURLSessionDataTask* task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { **dispatch_async(dispatch_get_main_queue(), ^{** //Handle data etc }); });
  • 请检查:我的第一个答案是错误的......无论您在method1WithCompletion:method2WithCompletion: 中拥有什么都无关紧要。方法一中的完成块被调用时,方法二被调用,方法二中的完成块被调用时,方法三被调用。
  • 好的,感谢您更新的答案。我会试一试,让你知道
【解决方案2】:

已编辑: 我不这么认为了,cjwirth 在 cmets 中驳斥了我下面的假设

我认为serial queue 仍然可以接近(但这只是假设,我没有检查它)。主要思想是将组的任务分派到串行队列中,在分派之前使用dispatch_group_enter(group),在方法1..2 完成时使用dispatch_group_leave(group)。让我展示一下它应该是什么:

dispatch_queue_t queue = dispatch_queue_create("com.example.MyQueue", NULL);
dispatch_group_t group = dispatch_group_create();

//METHOD 1
dispatch_group_enter(group);
dispatch_group_async(group, queue, ^{
   [self method1WithCompletion:^(BOOL success){
   dispatch_async(queue, ^{                     
                     dispatch_group_leave(group);
             });
    }];
});

//METHOD 2
dispatch_group_enter(group);
dispatch_group_async(group, queue, ^{
   [self method2WithCompletion:^(BOOL success){
   dispatch_async(queue, ^{                     
                     dispatch_group_leave(group);
             });
    }];
});

dispatch_group_notify(group,dispatch_get_main_queue(),^{
    //METHOD 3
});

注意:这种实现看起来有些不对劲。由于我们已经有了 NSOperationQueue,所以我建议您将 NSURLSessionDataTask 的内容包装到 NSOperation 中并按顺序执行

【讨论】:

  • 我一直在玩这样的实现,但它不起作用。问题是传递给dispatch_group_async 的块几乎立即完成(它只是触发了对method1WithCompletion 的异步调用,它不等待完成)。所以方法 1 和 2 几乎是瞬间被调用的,当它们都完成时调用 3。我用this测试,你可以看到它不起作用:(
  • 同理,我认为NSOperation 会遇到和 GCD 一样的等待完成的问题……我没怎么用过,所以我可能错了。跨度>
  • 是的,我检查了你的测试代码,你是完全正确的!至于NSOperation,简而言之,串行操作队列在前一个完成之前不会开始下一个排队的操作,您可以在method1..2完成时更改操作的完成状态。此外,操作具有使它们以适当的顺序执行的依赖性。这也需要检查。我稍后会做一些示例代码
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-10-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多