【问题标题】:Objective-C – Waiting for two async methods to completeObjective-C – 等待两个异步方法完成
【发布时间】:2023-03-16 20:58:01
【问题描述】:

我正在调用四个要以同步顺序执行的方法,前两个方法是同步的,后两个方法是异步的(从 URL 获取数据)。

伪代码:

- (void)syncData {

    // Show activity indicator
    [object sync]; // Synchronous method
    [object2 sync]; // Synchronous method
    BOOL object3Synced = [object3 sync]; // Async method
    BOOL object4Synced = [object4 sync]; // Async method
    // Wait for object3 and object4 has finished and then hide activity indicator
}

我怎样才能做到这一点?

【问题讨论】:

  • 这里伪代码不好。为了帮助我们,我们必须知道您使用的是哪种异步机制。
  • @PeterWarbo 如果object3object4 有一些界面可以在他们的操作完成时通知您,您需要编辑您的帖子并向我们展示该界面。
  • object3 正在通过NSURLRequest 下载文件,object4 正在使用 Facebook SDK 下载数据(我相信幕后也在使用 NSURLRequest

标签: objective-c ios cocoa asynchronous wait


【解决方案1】:

使用障碍:

void dispatch_barrier_async(dispatch_queue_t queue, dispatch_block_t block);

为异步执行提交屏障块并立即返回。

当屏障块到达私有并发的前面时 队列,它不会立即执行。 相反,队列一直等待,直到其当前正在执行的块完成执行。 那时, queue 自己执行屏障块。之后提交的任何块 屏障块在屏障块完成之前不会执行。

此示例输出 1 2 3 4 done 尽管是异步的,但它可能是 1 2 4 3 done。既然我知道你想处理一个活动指示器,这应该没关系。

#import <Foundation/Foundation.h>
int main(int argc, char *argv[]) {
    @autoreleasepool {
        dispatch_queue_t queue = dispatch_queue_create("com.myqueue", 0);
        dispatch_sync(queue,  ^(){NSLog(@"1");} );
        dispatch_sync(queue,  ^(){NSLog(@"2");});
        dispatch_async(queue, ^(){NSLog(@"3");});
        dispatch_async(queue, ^(){NSLog(@"4");});
        dispatch_barrier_sync(queue, ^(){NSLog(@"done");});
    }
}

其他测试异步代码的方法见:https://stackoverflow.com/a/11179523/412916

【讨论】:

  • 如果您不介意并发执行异步方法,请在创建队列时使用DISPATCH_QUEUE_CONCURRENT(iOS 5 中可用)而不是 0。
  • 这假设两个异步操作都在同一个队列中,并且该队列可以从调度屏障的代码中访问。
【解决方案2】:

假设您实际上有某种方式知道异步方法何时完成,您可能想要的是:

- (void)syncData {

    // Show activity indicator
    [object sync]; // Synchronous method
    [object2 sync]; // Synchronous method

    _object3Synced = _object4Synced = NO;
    [object3 syncWithCompletionHandler:
          ^{
               _object3Synced = YES;
               [self considerHidingActivityIndicator];
          }]; // Async method
    [object4 syncWithCompletionHandler:
          ^{
               _object4Synced = YES;
               [self considerHidingActivityIndicator];
          }]; // Async method
}

- (void)considerHidingActivityIndicator
{
     if(_object3Synced && _object4Synced)
     {
         // hide activity indicator, etc
     }
}

【讨论】:

  • 这与我想象的使用块完成处理程序实现它的方式大致相同...感谢您的输入
  • +1 - 当然 object4 方法不能依赖于 object3 方法调用的处理 ...
【解决方案3】:

您可以创建UIActivityInidicator 的子类,添加activityCount 属性并实现这两个附加方法:

- (void)incrementActivityCount
{
    if(_activityCount == 0)
    {
        [self startAnimating];
    }
    _activityCount++;
}

- (void)decrementActivityCount
{
    _activityCount--;
    if(_activityCount <= 0)
    {
        _activityCount = 0;
        [self stopAnimating];
    }
}

现在,每当您开始使用活动计数器调用incrementActivityCount 并在其完成块中(或以其他方式完成时)调用decrementActivityCount。如果你想在这些方法中做其他事情,上面只是一个简单的例子,在大多数情况下可能就足够了(特别是如果你设置了hidesWhenStopped = YES)。

【讨论】:

  • @Daij-Djan 当然,这些应该在主线程上调用,就像任何触及 UI 的东西一样。每当您处理完成块以更新 UI 时,您都应确保将它们分派到主队列。
【解决方案4】:

您需要启动第一个 Async 方法并使用完成块。在第一个异步方法的完成块中,您将启动第二个异步方法。虽然这种方式使得使用异步方法无关紧要。

【讨论】:

  • 是的,你失去了使两个异步调用并行的好处,但你并没有失去所有的好处——至少它脱离了 UI 线程并且不会挂起。如果第二个异步方法依赖于第一个异步方法的处理,那么这就是要走的路。否则其他答案会更好。
  • 是的,顺便说一句,我没有投反对票 - OPs 的问题与伪代码模棱两可。此外,如果它们相互依赖,您的答案会更好。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-10-19
  • 2014-08-09
  • 2013-02-15
  • 1970-01-01
  • 1970-01-01
  • 2013-08-19
  • 2020-10-04
相关资源
最近更新 更多