2015-04-07 2 views
0

Я новичок в 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"); 
     } 
    }]; 
} 

ответ

0

После много отладки и терпения мне удалось выявить проблему. Это не имело никакого отношения к параллелизму и было глупой ошибкой в ​​моем предикате. Я использовал следующую строку кода:
[fetch setPredicate:[NSPredicate predicateWithFormat:@"shopID==%@", shopID]];

я неправильно используя shopID в NSString время в моей модели данных ядра и NSManagedObject это был NSNumber. Я пересмотрел измененный идентификатор магазина, который будет храниться как NSString, и теперь он отлично работает. Однако я до сих пор не могу объяснить, почему он работал иногда, а иногда и не ...

1

Ваше предположение, скорее всего, правильно. Вы не следуете своему шаблону, используя один контекст для представления пользовательского интерфейса и один для фоновой выборки.

Итак, ваш первый курс действий должен состоять в использовании надлежащего фонового контекста для импорта и контекста для отображения для отображения.

Тем не менее, я думаю, было бы логичнее, чтобы родительский контекст был основным контекстом пользовательского интерфейса и использовал дочерний контекст для работы в фоновом режиме. «Сохранение» по детскому контексту затем приведет изменения к пользовательскому интерфейсу.

Кроме того, убедитесь, что вы обрабатываете изменения, подписавшись на NSManagedObjectContextDidSaveNotification через NSNotificationCenter и правильно сменив изменения, а затем обновив свой интерфейс.

+0

Спасибо за вашу помощь, я пробовал использовать оба контекста, и я продолжал работать в той же проблеме. Я даже экспериментировал с остановкой потока синхронизации, но это тоже не помогло. То, что работало в конце, заключалось в создании нового MOC с тем же координатором, когда пользователи войдут в регион.Я не уверен, насколько это хорошо, и что именно было здесь проблемой. В принципе, оба других MOC не всегда могли получить объект – Georgi

+0

. В любом случае, не нужно беспокоиться, так как это обычная модель создания контекста * ad hoc * для выполнения фоновой работы. – Mundi

+0

Проблема скоро вернулась, и на самом деле это не было связано с параллелизмом. Я опубликовал новый ответ, это была глупая ошибка в моем предикате. Большое спасибо за вашу помощь, хотя, по крайней мере, теперь я лучше разбираюсь в параллелизме Core Data :) – Georgi

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

  • Нет связанных вопросов^_^