Я новичок в Core Data, и я просмотрел многие связанные с Cored Data вопросы, но я не могу полностью понять всю концепцию Core Data и параллелизма. Похоже, что есть один способ сделать это, но в последние годы он изменился, и теперь немного сложно отфильтровать, какая информация обновлена, а что нет. Я работаю над небольшим приложением, которое импортирует данные магазинов из веб-сервиса, представляет его пользователю и контролирует, когда пользователь входит в регион определенного магазина. Я использую два NSManagedObjectContext
, входящих в класс CoreDataHelper
. Это init
из CoreDataHelper
реализуются как синглтон:NSFetchRequest on didEnterRegion проблема параллелизма
- (id)init {
self = [super init];
if (!self) {return nil;}
_model = [NSManagedObjectModel mergedModelFromBundles:nil];
_coordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:_model];
_parentContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
[_parentContext performBlockAndWait:^{
[_parentContext setPersistentStoreCoordinator:_coordinator];
[_parentContext setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
}];
_context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[_context setParentContext:_parentContext];
[_context setMergePolicy:NSMergeByPropertyObjectTrumpMergePolicy];
return self;
}
Я использую _ context
для представления данных для пользователя и _parentContext
для импорта и синхронизаций данных на заднем плане. Моя проблема в том, когда пользователь входит в область и didEnterRegion
называется я использую следующий метод для извлечения NSManagedObject
для магазина в этом регионе
- (Shop*)findShopWithID:(NSString*)shopID
{
NSArray* fetchedObjects;
NSManagedObjectContext* context = [self getBackgroundManagedObectContext];
if(context==nil)
[self sendRemoteLog:@"Context is nil"];
NSFetchRequest* fetch = [[NSFetchRequest alloc] init];
NSEntityDescription* entityDescription = [NSEntityDescription entityForName:@"Shop" inManagedObjectContext:context];
[fetch setEntity:entityDescription];
[fetch setPredicate:[NSPredicate predicateWithFormat:@"shopID==%@", shopID]];
NSError* error = nil;
fetchedObjects = [context executeFetchRequest:fetch error:&error];
if ([fetchedObjects count] == 1)
return [fetchedObjects objectAtIndex:0];
else
{
[self sendRemoteLog:[NSString stringWithFormat:@"No object found for ID %@",shopID]];
return nil;
}
}
- (NSManagedObjectContext*)getBackgroundManagedObectContext
{
CoreDataHelper* cdh = [(AppDelegate*)[[UIApplication sharedApplication] delegate] cdh];
return [cdh backgroundSaveContext];
}
Однако иногда, не всегда, выборки запроса не находит магазин с данный идентификатор, даже если он на 100%. Тот факт, что эта проблема возникает только иногда, приводит меня к выводу, что это имеет какое-то отношение к параллелизму. Кроме того, я считаю, что это может быть связано с тем, что я использую тот же объект parentContext
здесь для выполнения выборки, а также для асинхронного импорта данных из веб-службы. Я должен, вероятно, изменить его, но я думаю, что это не единственная проблема.
EDIT: Вот сохранения механизма в CoreDataHelper
- (void)saveContext
{
if ([_context hasChanges]) {
NSError* error = nil;
if ([_context save:&error]) {
NSLog(@"_context SAVED changes to persistent store");
}
else {
NSLog(@"Failed to save _context: %@", error);
}
}
else {
NSLog(@"SKIPPED _context save, there are no changes!");
}
}
- (void)backgroundSaveContext {
// First, save the child context in the foreground (fast, all in memory)
[self saveContext];
// Then, save the parent context.
[_parentContext performBlock:^{
if ([_parentContext hasChanges]) {
NSError *error = nil;
if ([_parentContext save:&error]) {
NSLog(@"_parentContext SAVED changes to persistent store");
}
else {
NSLog(@"_parentContext FAILED to save: %@", error);
}
}
else {
NSLog(@"_parentContext SKIPPED saving as there are no changes");
}
}];
}
Спасибо за вашу помощь, я пробовал использовать оба контекста, и я продолжал работать в той же проблеме. Я даже экспериментировал с остановкой потока синхронизации, но это тоже не помогло. То, что работало в конце, заключалось в создании нового MOC с тем же координатором, когда пользователи войдут в регион.Я не уверен, насколько это хорошо, и что именно было здесь проблемой. В принципе, оба других MOC не всегда могли получить объект – Georgi
. В любом случае, не нужно беспокоиться, так как это обычная модель создания контекста * ad hoc * для выполнения фоновой работы. – Mundi
Проблема скоро вернулась, и на самом деле это не было связано с параллелизмом. Я опубликовал новый ответ, это была глупая ошибка в моем предикате. Большое спасибо за вашу помощь, хотя, по крайней мере, теперь я лучше разбираюсь в параллелизме Core Data :) – Georgi