2016-03-12 4 views
1

Я хотел бы обновить дочерний контекст при обновлении родительского контекста.Ребенок NSManagedObjectContext обновление от родителя

У меня есть NSFetchedResultsController с помощью контекста ребенка, что я тогда хотел, чтобы обновить пользовательский интерфейс через это делегат - я не уверен, если это абсолютно правильный шаблон, вот что я делаю сейчас:

Я создаю дочерний контекст, который обновляется из веб-службы в классе, который поддерживает мою модель. Это упрощенный пример:

class Messages { 

var pmoc: NSManagedObjectContext! 
var delegate: MessagesDelegate? 

init() { 

    let appDel = UIApplication.sharedApplication().delegate as! AppDelegate 
    let moc  = appDel.managedObjectContext 

    let pmoc = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType) 
    pmoc.parentContext = moc 
    self.pmoc = pmoc 
} 

func dataToUpdatePrivateContextReceived() { 

    // Add things to the private moc 
    self.pmoc.performBlock {() -> Void in 

     // Create new NSManagedOBject, etc. 
     self.savePMOC() 
    } 
} 

func savePMOC() { 

    self.pmoc.performBlock {() -> Void in 

     do { 

      try self.pmoc.save() 
      // save main context through an abstraction... 
      // Inform any delegate a save has taken place 
      self.delegate?.pmocSavedIntoMain() 

     } catch let error as NSError { 

      print("Save pmoc error :\(error.localizedDescription)") 
     } 
    } 
} 
} 

protocol MessagesDelegate { 
    func pmocSavedIntoMain() 
} 

Тогда в некоторой UIViewController Я использую NSFetchedResultsController обновить UITableView, я пытаюсь использовать этот контроллер с собственным частным контексте, так что это обновление не блокирует пользовательский интерфейс. Другой упрощенный пример:

class ViewController: UIViewController { 

var fetchedResultsController: NSFetchedResultsController! 
var viewPMOC: NSManagedObjectContext! 
let messages = Messages() 

override func viewDidLoad() { 
    super.viewDidLoad() 
    // Do any additional setup after loading the view, typically from a nib. 

    messages.delegate = self 

    let appDel = UIApplication.sharedApplication().delegate as! AppDelegate 
    let moc  = appDel.managedObjectContext 

    let pmoc = NSManagedObjectContext(concurrencyType: .PrivateQueueConcurrencyType) 
    pmoc.parentContext = moc 
    self.viewPMOC = pmoc 

    let fr = NSFetchRequest(entityName: "MyEntity") 
    fr.fetchBatchSize = 20 

    let sort = NSSortDescriptor(key: "id", ascending: false) 
    fr.sortDescriptors = [sort] 

    self.fetchedResultsController = NSFetchedResultsController(fetchRequest: fr, 
     managedObjectContext: self.viewPMOC, 
     sectionNameKeyPath: nil, 
     cacheName: nil) 

    self.fetchedResultsController.delegate = self 

    do { 

     try self.fetchedResultsController.performFetch() 

    } catch let error as NSError { 

     print("vdl fetch error is: \(error.localizedDescription)") 
    } 
} 
} 

extension ViewController: NSFetchedResultsControllerDelegate { 

func controllerWillChangeContent(controller: NSFetchedResultsController) { 
    // dispatch begin updates on maind thread 
} 

func controller(controller: NSFetchedResultsController, didChangeObject anObject: AnyObject, atIndexPath indexPath: NSIndexPath?, forChangeType type: NSFetchedResultsChangeType, newIndexPath: NSIndexPath?) { 
    // handle update type on main thread 
} 

func controllerDidChangeContent(controller: NSFetchedResultsController) { 
    // dispatch end upds on main thread 
} 
} 

extension ViewController: MessagesDelegate { 
func pmocSavedIntoMain() { 
    // what can I do here to get the child context to update from 
    //parent and thus trigger the fetched results controller to update the view? 
} 
} 

ответ

1

Контроллер получаемых результатов нуждается в основном контексте.

Используйте этот шаблон, чтобы избавиться от «choppiness».

RootContext (private queue) - saves to persistent store 
MainContext (main queue) child of RootContext - use for UI (FRC) 
WorkerContext (private queue) - child of MainContext - use for updates & inserts 

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

Убедитесь, что вы используете методы блоков performBlock и performBlockAndWait во время работы с детскими контекстами.

+0

ah ha! Я никогда не думал делать это таким образом, но, видя это, это имеет такой смысл. Я скоро обновлю свой проект, спасибо! –

+0

Как получить объекты из базы данных? Какой контекст лучше всего использовать? –

+0

@PabloMartinez FRC должен позаботиться об этом с точки зрения производительности, поэтому вам не нужна фоновая фраза для извлечения. – Mundi

0

Я пытаюсь использовать этот контроллер с собственным частным контексте так это обновление не блокирует пользовательский интерфейс

работа КОП в жизни является обновите UI, хотя - этот должен быть в основном потоке, по сравнению с вашим упоминанием, частный контекст, который загружает данные. Я вернул бы FRC в ваш основной контекст (который затем будет автоматически обновляться при сохранении вашего детского контекста вверх) и оставить его там, если у вас нет проблем с производительностью. Тогда вы можете посмотреть на более экзотические вещи, но FRC нацелен на то, чтобы поддерживать высокую производительность благодаря таким вещам, как batchSize.

+0

Когда у меня много обновлений и вызывается insertRow, он становится довольно изменчивым, похоже, что он начинает смягчать приличную часть этого. Мне просто не хватает, когда обновления будут восстановлены обратно в основной контекст после его существования. –

+1

Взгляните на реализацию в этом вопросе: http://stackoverflow.com/questions/31722142/coredata-private-context-with-child-main-context-fetchedresultscontroller-not?rq=1 – sschale

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