Ответ 1
Да - это действительно так легко сейчас (в iOS 5.0). Для совместимости с iOS 4 предыдущие препятствия остаются, но документация не так уж плоха при ограничении потоков. Может быть, вы должны добавить это в раздел wiki?
Неужели это сейчас так просто в iOS5?
Я использовал фоновый выбор, используя этот код в приложении AppDelegate:
dispatch_queue_t downloadQueue = dispatch_queue_create("DownloadQueue", NULL);
dispatch_async(downloadQueue, ^{
self.myDownloadClass = [[MyDownloadClass alloc]initInManagedObjectContext:self.managedObjectContext];
[self.myDownloadClass download];
});
dispatch_release(downloadQueue);
Мой класс загрузки выполняет NSURLConnection для извлечения некоторых данных XML, использует NSXMLParser для анализа данных, а затем обновляет сложную схему в основных данных. Я бы всегда переключился на основной поток, чтобы фактически обновить основные данные. Мессиальный код с большим количеством вызовов dispatch_sync (dispatch_get_main_queue()....
Мой новый код выглядит следующим образом:
NSManagedObjectContext *child = [[NSManagedObjectContext alloc]initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[child setParentContext:self.managedObjectContext];
[child performBlock:^{
self.myDownloadClass = [[MyDownloadClass alloc]initInManagedObjectContext:child];
[self.myDownloadClass download];
}];
вместе с небольшим изменением на некоторый другой код в моем AppDelegate, чтобы установить тип контекста объекта родительской модели в NSMainQueueConcurrencyType:
- (NSManagedObjectContext *)managedObjectContext
{
if (__managedObjectContext != nil)
{
return __managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil)
{
__managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[__managedObjectContext setPersistentStoreCoordinator:coordinator];
}
return __managedObjectContext;
}
Кажется, что он работает очень хорошо. Весь процесс обновления по-прежнему выполняется в отдельном потоке, но мне не нужно создавать поток. Похоже на магию.
Просто помните, хотите ли вы зафиксировать свои изменения в файлах данных физического ядра, у вас есть вызов save: в родительском контексте.
Я не задавал здесь вопроса. Я публикую это, чтобы он помогал другим, потому что все, что я нашел при поиске новых методов контекста управляемого объекта iOS5, давало только подробные сведения о высоком уровне без примеров кода. И все остальные поисковые запросы по извлечению основных данных в фоновом режиме старые, иногда очень старые, и обсудите, как сделать это до iOS5.
Да - это действительно так легко сейчас (в iOS 5.0). Для совместимости с iOS 4 предыдущие препятствия остаются, но документация не так уж плоха при ограничении потоков. Может быть, вы должны добавить это в раздел wiki?
Я пытаюсь понять, как реализован этот новый API. Моя обычная схема для многопоточных данных ядра выглядит примерно так:
Обычно в NSOperation
, но упрощенном использовании dispatch_async
в этом примере:
dispatch_queue_t coredata_queue; // some static queue
dispatch_async(coredata_queue, ^() {
// get a new context for this thread, based on common persistent coordinator
NSManagedObjectContext *context = [[MyModelSingleton model] threadedContext];
// do something expensive
NSError *error = nil;
BOOL success = [context save:&error];
if (!success) {
// the usual.
}
// callback on mainthread using dispatch_get_main_queue();
});
Затем основной поток ответит обновлением пользовательского интерфейса на основе NSManagedObjectContextDidSaveNotification
, чтобы объединить основной контекст.
Новый API, похоже, является оберткой вокруг этого шаблона, где контекст child
выглядит так, будто он просто переносит постоянный координатор из своего родителя, чтобы создать новый контекст. И указывая NSPrivateQueueConcurrencyType
на init, убедитесь, что параметр performBlock
выполняется в частной очереди.
Новый API, похоже, не намного меньше кода для ввода. Любые преимущества перед "традиционной" резьбой?