Core Data NSPrivateQueueConcurrencyType и совместное использование объектов между потоками - PullRequest
36 голосов
/ 26 декабря 2011

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 и основной очередью?Нужно ли мне для этого использовать идентификаторы управляемого объекта?

Ответы [ 2 ]

66 голосов
/ 27 декабря 2011

Когда вы используете 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:] в его собственный метод. Вы также можете захотеть передать массив идентификаторов объектов обратно в контекст основного потока вместо того, чтобы выполнять блок для каждого идентификатора объекта. Это зависит от ваших потребностей.

3 голосов
/ 05 августа 2012

Как объясняет Даниэль Эггерт, это определенно все еще так.Исключение составляет NSMainQueueConcurrencyType, где вы также можете безопасно использовать контекст и объекты управляемого объекта в основном потоке (а также из других потоков через механизм executeBlock).Полезность этого не может быть преуменьшена!

В iOS 5 также представлена ​​концепция родительских контекстов, которая также значительно упрощает фоновые операции и устраняет необходимость беспокоиться об использовании уведомлений для распространения изменений между потоками.

Видео WWDC 2012 "Сессия 214 - Основные рекомендации по основным данным" содержит гораздо более подробную информацию по обоим предметам и является очень полным.Видео необходимо просматривать всем, кто использует Core Data.

...