2014-02-21 7 views
2

У меня есть одно сомнение в многопоточности в coredata. если мы используем многопоточность, мы должны использовать отдельный NSManagedObjectContext для вставки новых данных или обновления, иначе мы можем использовать метод родительского дочернего контекста. Но я создаю только новый NSManagedObjectContext. Мой вопрос заключается в том, что я должен использовать отдельный NSManagedObjectContext для равномерного выбора в фоновом потоке. Если нет (т. Е. Мы можем использовать только основную очередь NSManagedObjectContext), то почему я получаю ошибку __psynch_mutexwait.Запись данных многопоточности с базовыми данными

Спасибо,

+1

Покажите код, который вы указали, на самом деле не слишком много объясняет –

ответ

17

Во-первых, основные данные являются потокобезопасными. Однако вы должны соблюдать следующие правила:

  1. NSManagedObjectContext - связанная тема. Вы можете использовать его только в потоке, которому он назначен. -init вызывает привязку контекста к потоку, в который он был создан. Использование -initWithConcurrencyType: позволит вам создавать контексты, связанные с другими потоками/очередями.
  2. Любого NSManagedObject, связанный с NSManagedObjectContext привязан к одной и той же нити/очереди в контексте она пришла
  3. Там нет третьих правил

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

Как и большинство вещей, которые я делаю; Это не общее решение. Это базовый уровень, который должен корректироваться на основе каждого проекта.

+0

Важно ли отметить, что NSManagedObjectID должен быть постоянным до потокобезопасности (если это правильно)? – 3lvis

+1

Нет, это неправильно. «NSManagedObjectID» является изменяемым объектом, а Core Data будет мутировать его при сохранении, и идентификатор перемещается с временного на постоянный. Лично я не рекомендую использовать 'NSManagedObjectID'. Есть лучшие решения. –

+2

Маркус, это самое сжатое объяснение Threading Core Data, которое я прочитал. Используя его с момента его введения, есть дни, когда я до сих пор ошибаюсь в этих правилах! Вы упоминаете «лучшие решения» - можете ли вы уточнить? –

Смежные вопросы