我应该如何在iOS中使用GCD dispatch_barrier_async(似乎在其他块之前而不是之后执行)



我正在尝试在iOS5中同步以下代码:

  1. 一个对象有一个发出 HTTP 请求的方法,从中发出 HTTP 请求获取一些数据,包括图像的 URL
  2. 数据到达后,文本数据将用于填充核心数据模型
  3. 同时,异步调度第二个线程进行下载图像;此线程将通过 KVO 向视图控制器发出信号,当映像已缓存并在 CoreData 模型中可用。
  4. 由于图像下载需要一段时间,我们立即返回具有所有属性的 CoreData 对象,但图像调用方。
  5. 此外,当第二个线程完成下载时,CoreData 模型可以保存。

这是(简化的)代码:

- (void)insideSomeMethod
{
    [SomeHTTPRequest withCompletionHandler:
     ^(id retrievedData) 
     {
         if(!retrievedData)
         {
             handler(nil);
         }
         // Populate CoreData model with retrieved Data...
         dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
             NSURL* userImageURL = [NSURL URLWithString:[retrievedData valueForKey:@"imageURL"]];
             aCoreDataNSManagedObject.profileImage = [NSData dataWithContentsOfURL:userImageURL];
         });
         handler(aCoreDataNSManagedObject);
         [self shouldCommitChangesToModel];
     }];
}
- (void)shouldCommitChangesToModel
{
    dispatch_barrier_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
        NSError *error = nil;
        if(![managedObjectContext save:&error]) 
        {
            //  Handle error
        }  
    });
}
但是现在的情况

是,基于屏障的保存块总是在图像加载块之前执行。那是

dispatch_barrier_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
            NSError *error = nil;
            if(![managedObjectContext save:&error]) 
            {
                //  Handle error
            }  
        });

在以下之前执行:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
                 NSURL* userImageURL = [NSURL URLWithString:[retrievedData valueForKey:@"imageURL"]];
                 aCoreDataNSManagedObject.profileImage = [NSData dataWithContentsOfURL:userImageURL];
             });

所以显然我并没有真正在屏障之前调度图像加载块,或者屏障会等到图像加载块完成后再执行(这是我的意图)。

我做错了什么? 如何确保图像加载块在屏障块之前排队?

乍一看,问题可能是您在全局并发队列上调度屏障块。您只能在自己的自定义并发队列上使用屏障块。 根据 dispatch_barrier_async 上的 GCD 文档,如果您将块调度到全局队列,它的行为将类似于正常的dispatch_async调用。

Mike Ash 有一篇关于 GCD 屏障块的好博客文章: http://www.mikeash.com/pyblog/friday-qa-2011-10-14-whats-new-in-gcd.html

祝你好运

T

您需要创建自己的队列,而不是按照 ADC 文档调度到全局队列

指定的队列应该是您创建的并发队列 自己使用dispatch_queue_create功能。如果排队你 传递给此函数的是串行队列或全局队列之一 并发队列,此函数的行为类似于dispatch_async 功能。

从 https://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html#//apple_ref/c/func/dispatch_barrier_async.

您可以创建大量自己的 GCD 队列。 GCD 队列非常小,您可以毫无问题地创建大量 GCD 队列。你只需要在完成它们后释放它们。

对于您似乎试图解决的问题,dispatch_barrier_async可能不是最好的解决方案。请查看并发编程指南的"从线程迁移"部分。只需在您自己的串行队列上使用dispatch_sync就可以解决同步问题。或者,您可以使用 NSOperation 和 NSOperationQueue。与 GCD 不同,NSOperation 允许您轻松管理依赖项(您可以使用 GCD 执行此操作,但它可能会很快变得丑陋)。

我参加聚会有点晚了,但也许下次你可以尝试利用dispatch_group来发挥自己的优势。 http://www.raywenderlich.com/63338/grand-central-dispatch-in-depth-part-2

相关内容

最新更新