Основные данные NSPrivateQueueConcurrencyType и совместное использование объектов между потоками
В iOS 5 появился новый способ быстрого получения данных в фоновом потоке путем инициализации MOC с помощью NSPrivateQueueConcurrencyType
, а затем выполнения выборки в performBlock:
Одним из основных принципов Core Data было то, что вы не можете совместно использовать управляемый объект между потоками/очередями. Остается ли дело с performBlock:
? Есть следующее:
[context performBlock:^{
// fetch request code
NSArray *results = [context executeFetchRequest:request error:nil];
dispatch_async(dispatch_get_main_queue(), ^(void) {
Class *firstObject = [results objectAtIndex:0];
// do something with firstObject
});
}];
все еще неприемлемо, так как я делюсь своим массивом результатов/объектами между очередью bg и основной очередью? Должен ли я использовать идентификаторы управляемых объектов для этого?
Ответы
Ответ 1
При использовании NSPrivateQueueConcurrencyType
вам нужно сделать все, что касается этого контекста или любого объекта, принадлежащего этому контексту, внутри метода -performBlock:
.
Ваш код выше является незаконным, поскольку вы передаете эти объекты обратно в основную очередь. Однако новый API помогает вам в решении этого: вы создаете один контекст, связанный с основной очередью, т.е. С NSMainQueueConcurrencyType
:
// Assume we have these two context (They need to be set up. Assume they are.)
NSManagedObjectContext *mainMOC = [[[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType] autorelease];
NSManagedObjectContext *backgroundMOC = [[[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType] autorelease];
// Now this can safely be called from ANY thread:
[backgroundMOC performBlock:^{
NSArray *results = [backgroundMOC executeFetchRequest:request error:nil];
for (NSManagedObject *mo in results) {
NSManagedObjectID *moid = [mo objectID];
[mainMOC performBlock:^{
NSManagedObject *mainMO = [mainMOC objectWithID:moid];
// Do stuff with 'mainMO'. Be careful NOT to use 'mo'.
}];
}
}];
Это становится менее запутанным, если вы переместите внутренний вызов [mainMOC performBlock:]
в свой собственный метод. Вы также можете передать массив идентификаторов объектов обратно в контекст основного потока вместо выполнения блока для каждого идентификатора объекта. Это зависит от ваших потребностей.
Ответ 2
Как объясняет Даниэль Эггерт, это определенно все еще так. Исключение составляет NSMainQueueConcurrencyType
, где вы также можете безопасно использовать контекст и объекты управляемого объекта в основном потоке (а также из других потоков через механизм executeBlock). Полезность этого нельзя недооценивать!
iOS 5 также представила концепцию родительских контекстов, которая также значительно упрощает фоновые операции и устраняет необходимость беспокоиться об использовании уведомлений для распространения изменений между потоками.
WWDC 2012 видео "Сессия 214 - Основные рекомендации по основным данным" более подробно описывает обе темы и является очень всеобъемлющей. Видео является важным просмотром для тех, кто использует Core Data.