【问题标题】:iOS Objective-C wait for async processiOS Objective-C 等待异步进程
【发布时间】:2014-06-20 06:29:25
【问题描述】:

我在 AppDelegate 中调用下面的代码:

-(void) application:(UIApplication *)application performFetchWithCompletionHandler:
(void (^)(UIBackgroundFetchResult))completionHandler {


-(BOOL)backgroundRefresh{
    newData = false;
    callStartTime = [NSDate date];

    [self processAll];
       dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        while(!fetchComplete);
        NSLog(@"NOW COMPLETE");

   });
    NSLog(@"Got here now!");
    return newData;
}

对 [self processAll] 的调用会运行具有异步调用等的代码,并将继续循环直到所有活动完成,反复调用自身。所有任务完成后,fetchComplete 设置为 true。这部分工作正常。

我需要代码等待 fetchComplete 为真,然后将 bool 返回给 AppDelegate。

问题是,非常正确的是,当前检查虽然可以显示 NSLogs 等,但对于将 BOOL 返回给调用者没有用,因为该过程当前是异步的。我已将其设置为异步以便它运行,否则,我发现 processAll 代码被阻止运行。

有人可以解释一下我如何监控 fetchComplete,并且只有在这种情况下才将布尔值返回给调用函数?

我尝试在 while 返回后将 return to 移动到异步块中,但这会由于在块内调用而返回语法错误。

【问题讨论】:

  • 你不能只是等待异步任务完成才能返回,毕竟这会使它同步,你必须使用一些委托或 NSNotificationCenter 来告诉相关方获取完成并获取他们的数据。
  • while(!fetchComplete); 不要那样做。曾经。这是一个繁忙的轮询,它会尽可能快地旋转 CPU 的至少一个核心,而不会做任何有用的事情。它会消耗电池寿命并降低整体性能。
  • 感谢 cmets 的支持。已经接受了所有这些,包括我不应该使用 while(!fecttComplete) 的事实。再次感谢您。

标签: ios objective-c asynchronous while-loop wait


【解决方案1】:

你试图解决这个问题的庄园有点不典型。

这通常通过委托blocksnotifications 完成。

你只想在一些异步方法完成之后执行一些function

假设我们有一个名为 AyncProcessor 的异步处理器。

AyncProcessor * processor = [AyncProcessor sharedProcessor];
processor.delegate = self;
[processor start];

是一种相当常见的委托方式。这里的假设是有一个协议定义了一个回调方法,该方法在完成时运行。

//protocol method
-(void) processingComplete;

// and at some point in AsyncProcessor
[self.delegate processingComplete] 

更多关于委派的信息here

也可以使用方块

AyncProcessor * processor = [AyncProcessor sharedProcessor];
[processor start:^()/{
  ///code in this block will complete after processing has completed
 }];

更多关于区块的信息请见here

如前所述,您可以发送NSNotification

对于您的问题,委派可能是个好主意。

【讨论】:

  • 感谢您的 cmets。我已经使用通知,因为我觉得它在特定情况下更适合自己,但是,我还要记住你的 cmets 以供将来参考。再次感谢。
【解决方案2】:

您无需等待异步进程完成。这使它同步。你需要改变你的想法。

有许多不同的方式来处理异步 API。

  1. 传入一个完成块
  2. 分配一个委托并定义一个在完成时被调用的方法。
  3. 流程完成时发送通知。

毫无疑问,但异步 API 的整体理念是它会立即返回,您不必等待它完成。正如另一个人所说,永远不要使用像while(!fetchComplete) 这样的代码。这是一个非常糟糕的主意。

【讨论】:

  • 感谢 cmets 的支持。已经接受了所有这些,包括我不应该使用 while(!fecttComplete) 的事实。再一次感谢你。我已经使用通知。
  • 有时你想要一个同步的api,但你可能只提供了异步函数。当您从后台线程调用方法时,您可能会认为该方法是同步的。在这种情况下,您可能必须强制同步异步方法。
  • @paranoidcoder,是的,有时需要这样做,但永远不要在主线程上,通常你会使用锁或信号量之类的东西。
【解决方案3】:

使用通知。首先,你必须像这样开始收听通知

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(fetchDidComplete)
                                             name:@"fetchDidComplete"
                                           object:nil];

无论您在哪里将 fetchComplete 设置为 true,都可以发布这样的通知

[[NSNotificationCenter defaultCenter] postNotificationName:@"fetchDidComplete"
                                                    object:self
                                                  userInfo:nil];

那么您应该有一个名为 fetchDidComplete 的方法来完成后完成工作。 完成后不要忘记停止收听通知。

[[NSNotificationCenter defaultCenter] removeObserver:self
                                                name:@"fetchDidComplete"
                                              object:nil];

【讨论】:

  • 还要确保您在主线程上发布通知。
  • 感谢您的 cmets。阅读了不同的回复(并接受了 cmets(谢谢大家)),我觉得由于调用流程的方式,我认为通知是要走的路。但是,虽然我相信我可以理解如何发布通知,但我试图了解如何在 AppDelegate 的完成处理程序中使用监听。实际上,我在问如何使用结果调用完成处理程序,并在该原始代码中删除观察者?提前致谢。
  • 你可以在这里找到详细的答案stackoverflow.com/questions/2191594/…
  • 谢谢。我才看到你的回复,不过我现在已经整理好了。我在通知中使用了块,因此我能够调用完成块。我刚刚查看了链接,这也表明了这一点。非常感谢你的帮助。非常感谢。
猜你喜欢
  • 2011-05-10
  • 1970-01-01
  • 2018-02-07
  • 2023-03-16
  • 1970-01-01
  • 1970-01-01
  • 2017-04-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多