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