Core Data import: how do I improve performance when merging data into the view context?

I'm trying to import a largish set of data (150,000 records) over the network into a Core Data SQLite store. The current requirements are to download this data continuously in batches (100 records at a time), persist it, and display it in a table view as soon as possible to be scrolled through.

My data provider class exposes the view context for display, and uses a background context to import the data. The same background context is reused on each import of a batch, and is reset before the next one. The initializer for the Provider class looks something like this:


init(persistentContainer: NSPersistentContainer) {
  self.persistentContainer = persistentContainer
  viewContext = persistentContainer.viewContext
  viewContext.automaticallyMergesChangesFromParent = true
  viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
  backgroundContext = persistentContainer.newBackgroundContext()
  backgroundContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
}

The import function looks like:

func importBatch(_ batch: [JsonData]) {
    backgroundContext.perform {
        for data in batch {
            let newObject = NSEntityDescription.insertNewObject(forEntityName: "Entity", into: backgroundContext)
            try! newObject.update(with: data)
        }

        if backgroundContext.hasChanges {
            try! backgroundContext.save()
            backgroundContext.reset()
        }
    }
}

For display, I'm currently using a fetched results controller with a fetch batch size on the fetch request. What I'm noticing is that, starting at around 10,000 record imports, the UI in the table view starts to stutter. The main cause appears to be the merge into the view context. When manually merging (i.e. when viewContext.automaticallyMergesChangesFromParent = false, it occurs here:

@objc func backgroundContextDidSave(_ notification: Notification) {
    self.viewContext.perform {
        self.viewContext.mergeChanges(fromContextDidSave: notification)
    }
}

Given the current requirements, is there anything I can do to address this? In the meantime, I've tried the following, which offer some benefits, but haven't addressed the root problem:

  • Persistent history tracking: here I tried merging into the view context only every 10 batches. Smoother scrolling, but longer pauses on the merge
  • Batch inserts: has better performance when saving, but same UI stutters when merging
Core Data import: how do I improve performance when merging data into the view context?
 
 
Q