Во-первых, основные данные являются потокобезопасными. Однако вы должны соблюдать следующие правила:
NSManagedObjectContext
- связанная тема. Вы можете использовать его только в потоке, которому он назначен. -init
вызывает привязку контекста к потоку, в который он был создан. Использование -initWithConcurrencyType:
позволит вам создавать контексты, связанные с другими потоками/очередями.
- Любого
NSManagedObject
, связанный с NSManagedObjectContext
привязан к одной и той же нити/очереди в контексте она пришла
- Там нет третьих правил
Вы можете передать NSManagedObjectID
экземпляров между потоками, но правилами 1 и 2 должны соблюдаться. Из вашего описания я считаю, что вы нарушаете эти правила.
Лично я не рекомендую использовать NSManagedObjectID либо. Есть лучшие решения. - Marcus S. Zarra
Маркус, это самое сжатое объяснение Threading Core Data, которое я прочитал. Используя его с момента его введения, есть дни, когда я до сих пор ошибаюсь в этих правилах! Вы упоминаете «лучшие решения» - можете ли вы уточнить?
У меня довольно сильное недоверие в отношении использования NSManagedObjectID
. Во многих ситуациях он не остается неизменным с одного жизненного цикла приложения на другой. Первоначально, основываясь на документации, мы (разработчики какао в целом) полагали, что для нас создан наш мифический первичный ключ. Это оказалось неверным.
В современном развитии с родительскими/детскими контекстами пейзаж еще более запутанный, и есть некоторые интересные ловушки, за которыми нам нужно следить. Учитывая нынешний пейзаж, мне это не нравится больше, чем раньше. Итак, что мы используем?
Мы должны генерировать наши собственные. Это не должно быть много. Если ваши данные уже не имеют первичного ключа с сервера (довольно распространенный, чтобы иметь id
с сервера на основе Ruby), то создайте его. Я хотел бы назвать его guid
, а затем иметь -awakeFromInsert
похожее на это:
- (void)awakeFromInsert
{
[super awakeFromInsert];
if (![self primitiveValueForKey:@"guid"]) {
[self setPrimitiveValue:[[NSProcessInfo processInfo] globallyUniqueString] forKey:@"guid"];
}
}
ПРИМЕЧАНИЕ: Этот код записывается в веб-браузере и не может скомпилировать.
Вы проверяете значение, потому что -awakeFromInsert
вызывается один раз для каждого контекста.Тогда я, как правило, имеют удобный метод на моих NSManagedObject
экземпляров подобных:
@implementation MyManagedObject
+ (MyManagedObject*)managedObjectForGUID:(NSString*)guid inManagedObjectContext:(NSManagedObjectContext*)context withError:(NSError**)error
{
NSFetchRequest *fetch = [NSFetchRequest fetchRequestWithEntityName:[self entityName]];
[fetch setPredicate:[NSPredicate predicateWithFormat:@"guid == %@", guid]];
NSArray *results = [context executeFetchRequest:request error:error];
if (!results) return nil;
return [results lastObject];
}
@end
ПРИМЕЧАНИЕ: Этот код записывается в веб-браузере и не может скомпилировать.
Это оставляет обработку ошибок и управление контекстом/потоком до разработчика, но предоставляет удобный метод для извлечения объекта в текущем контексте и позволяет нам «отскакивать» объект из одного контекста в другой.
Это медленнее, чем -objectWithID:
и должны быть тщательно и используется только в тех ситуациях, когда вам нужно, чтобы подпрыгнуть объект из одного контекста в другой после сохранения перемещает его вверх по стеку.
Как и большинство вещей, которые я делаю; Это не общее решение. Это базовый уровень, который должен корректироваться на основе каждого проекта.
Покажите код, который вы указали, на самом деле не слишком много объясняет –