Как использовать GCD dispatch_barrier_async в iOS (кажется, выполняется до и после других блоков)
Я пытаюсь синхронизировать следующий код в iOS5:
- у объекта есть метод, который делает HTTP-запрос, из которого он
получает некоторые данные, включая URL-адрес изображения
- после поступления данных, текстовые данные используются для заполнения
Модель CoreDatali >
- в то же время второй поток отправляется async для загрузки
изображение; этот поток будет подавать сигнал через KVO в viewController, когда
изображение уже кэшировано и доступно в модели 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];
});
Итак, я действительно не отправляю блок загрузки изображения перед барьером, или барьер будет ждать, пока блок загрузки изображения не будет выполнен (что было моим намерением).
Что я делаю неправильно? как я могу убедиться, что блок загрузки изображения находится в очереди перед барьерным блоком?
Ответы
Ответ 1
На первый взгляд проблема может заключаться в том, что вы отправляете барьерный блок в глобальной параллельной очереди. Вы можете использовать блоки блокировки только в своей собственной параллельной очереди. В документах GCD на dispatch_barrier_async, если вы отправляете блок в глобальную очередь, он будет вести себя как обычный вызов dispatch_async.
Майк Эш имеет хорошее сообщение в блоге по блокам барьеров GCD: http://www.mikeash.com/pyblog/friday-qa-2011-10-14-whats-new-in-gcd.html
Удачи.
Т
Ответ 2
Вам нужно создать свою собственную очередь, а не отправлять в глобальные очереди в соответствии с документами 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 очень маленькие, и вы можете создавать их без проблем. Вам просто нужно освободить их, когда вы закончите с ними.
Ответ 3
Для того, что вы пытаетесь решить, dispatch_barrier_async
может быть не лучшим решением.
Посмотрите раздел Миграция из нитей" руководства по программированию Concurrency. Просто используя dispatch_sync
в вашей собственной последовательной очереди, вы можете решить вашу проблему синхронизации.
Кроме того, вы можете использовать NSOperation и NSOperationQueue. В отличие от GCD, NSOperation позволяет вам легко управлять зависимостями (вы можете делать это с помощью GCD, но это может стать уродливым).
Ответ 4
Я немного опаздываю на вечеринку, но, возможно, в следующий раз вы можете попробовать использовать dispatch_group
в ваших интересах. http://www.raywenderlich.com/63338/grand-central-dispatch-in-depth-part-2