2016-12-14 2 views
1

Я интегрировал рамки coredata в приложении iOS10 (Swift3), которое извлекает данные с сервера и дисплея. Когда приложение запускается в первый раз, у основных данных нет записей. После обмена некоторой информацией с сервером она начинает синхронизацию в фоновом потоке. Я могу видеть, что данные загружаются с сервера через веб-сервис, анализируются и хранятся в основных данных. Но если я уйду и запустим приложение, он покажет все записи.Coredata performFetch не получает новые записи

На мой взгляд, контроллер, я использую «NSFetchedResultsController» для отображения записей в «TableView». Я создаю сгружен контроллер результаты, как показано ниже:

fileprivate lazy var inspirationsResults: NSFetchedResultsController<Inspiration> = { 
    // Create Fetch Request 
    let fetchRequest: NSFetchRequest<Inspiration> = Inspiration.fetchRequest() 

    // Configure Fetch Request 
    fetchRequest.sortDescriptors = [NSSortDescriptor(key: "timeStamp", ascending: false)] 

    // Create Fetched Results Controller 
    let fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: CoreDataManager.shared.getContext(), sectionNameKeyPath: nil, cacheName: nil) 

    // Configure Fetched Results Controller 
    fetchedResultsController.delegate = self 

    return fetchedResultsController 
}() 

В методе viewDidLoad я написал ниже код для извлечения:

do { 
    try self.inspirationsResults.performFetch() 
} catch { 
    let fetchError = error as NSError 
    print("\(fetchError), \(fetchError.userInfo)") 
} 

Я также добавил методы делегата «controllerWillChangeContent, controllerDidChangeContent & didChangeObject» в обрабатывать обновления/модификации.

Я использую persistentContainer сохранить объект:

func addInspirations(_ inspirations:[[String: AnyObject]]) { 
    persistentContainer.performBackgroundTask({ (bgContext) in 
     bgContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy 

     for tInspiration in inspirations { 
      let inspiration = Inspiration(context: bgContext) 
      inspiration.inspirationID = tInspiration[kInspirationId] as! Int32 
      inspiration.inspirationName = tInspiration[kInspirationName] as? String 
     } 

     if bgContext.hasChanges { 
      do { 
       try bgContext.save() 
      } catch { 
       let nserror = error as NSError 
       fatalError("Unresolved error \(nserror), \(nserror.userInfo)") 
      } 
     } 
    }) 
} 

я упускаю что-нибудь?

+0

ли ваш фон и основные нити контексты, связанные с 'mergeChangesFromContextDidSaveNotification: '? Или это соединение родитель-ребенок? – bteapot

+0

@bteapot, я обновил свой код с помощью «сохранения» деталей. В том, что я устанавливаю mergePolicy фоновой задачи в NSMergeByPropertyObjectTrumpMergePolicy – Satyam

+0

'mergePolicy' не играет никакой роли в причине вашей проблемы. Я напишу ответ. – bteapot

ответ

0

Два или более NSManagedObjectContext s, которые извлекают данные из одного и того же постоянного хранилища, автоматически не отмечали изменения в этом магазине. Они должны быть связаны друг с другом, чтобы получать удаления, вставки и обновления, которые были выполнены в одном из них. Такая связь может быть установлена ​​одним из двух способов:

  1. Слияние изменений.
  2. Использование родительского/дочернего шаблона.

Слияние изменений обычно делается так:

// initializing your contexts 
self.mainContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; 
self.mainContext.persistentStoreCoordinator = self.coordinator; 

self.backgroundContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; 
self.backgroundContext.persistentStoreCoordinator = self.coordinator; 

[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(mainContextDidSave:) name:NSManagedObjectContextDidSaveNotification object:self.mainContext]; 
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(backgroundContextDidSave:) name:NSManagedObjectContextDidSaveNotification object:self.backgroundContext]; 

И где-то позже:

- (void)mainContextDidSave:(NSNotification *)notification 
{ 
    [self.backgroundContext performBlock:^{ 
     [self.backgroundContext mergeChangesFromContextDidSaveNotification:notification]; 
    }]; 
} 

- (void)backgroundContextDidSave:(NSNotification *)notification 
{ 
    [self.mainContext performBlock:^{ 
     [self.mainContext mergeChangesFromContextDidSaveNotification:notification]; 
    }]; 
} 

Это гарантирует, что контекст будет получать изменения сразу после того, что изменения сохраняются.

Одним из возможных родитель/ребенок вариации установки будет:

// when initializing your contexts 
self.mainContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; 
self.mainContext.persistentStoreCoordinator = self.coordinator; 

self.backgroundContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType]; 
self.backgroundContext.parentContext = self.mainContext; 

// when saving your background changes 
[self.backgroundContext performBlock:^{ 
    __block NSError *error; 

    if ([self.backgroundContext save:&error) { 
     [self.mainContext performBlock:^{ 

      if (![self.mainContext save:&error]) { 
       NSLog(@"Error saving main context"); 
      } 
     }]; 
    } else { 
     NSLog(@"Error saving background context"); 
    } 
}]; 

Это будет толкать изменения от фонового контекста в основной контекст и сохранить их в постоянном хранилище.

Кроме того, NSFetchedResultsController имеют свои особенности, такие как this или this.

И, наконец, если вам нужно импортировать относительно большой набор данных с несколькими десятками тысяч объектов, отключите NSFetchedResultsController с при сохранении и импорте данных. Это позволит вам сэкономить много времени на обработку основного потока.Вот схема:

  1. При обработке данных, размещать свои уведомления прямо перед сохранением фона контекст:

    [[NSNotificationCenter defaultCenter] postNotificationName:DBWillUpdateDataNotification object:self]; 
    
  2. Сохранить изменения и объединить их в основной контекст, или толкать их в родителю контекст и сохранить его.

  3. сообщение еще одно уведомление:

    [[NSNotificationCenter defaultCenter] postNotificationName:DBDidUpdateDataNotification object:self]; 
    
  4. Часы для этого два пользовательских уведомлений в контроллерах просмотра. При получении первого, установите delegate на nil на NSFetchedResultsController с. Это не позволит им учиться на изменения в контексте и сообщать о них. При получении второго - подключить делегат обратно, вызовите -performFetch: на вашем и ЦФО перезагрузить интерфейс, то есть позвонить -reloadData на виде таблицы, заселить пользовательские метки и т.д.

+0

Если я создаю контекст вручную, это будет работать. Но я использую «persistentContainer.performBackgroundTask» ({(bgContext) в », который предоставит нам контекст. Я попытался установить mainContext для« bgContext », доступный в закрытии, но его сбой как координатор уже установлен для этого. – Satyam

+0

Создание собственного контекста не проблема, это всего лишь пара строк. – bteapot

+0

Я следую «Слияниям с изменениями». У меня несколько параллельных проектов backgroundContext для обновления данных. Но я использую контекст основного управляемого объекта для обновления интерфейса . В моем случае также вызывается уведомление, но данные не обновляются в выбранном контроллере результатов. – Satyam

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

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