Understanding the use of multiple instances of NSManagedObjectContext

It has been mentioned several times in this chapter that you can use multiple managed object contexts. In many cases, you will only need a single managed object context. Using a single managed object context means that all of the code related to the managed object context is executed on the main thread. If you're performing small operations, that's fine. However, imagine importing large amounts of data. An operation such as that could take a while. Executing code that runs for a while on the main thread will cause the user interface to become unresponsive. This is not good, because the user will think your app has crashed. So how do you work around this? The answer is using multiple managed object contexts.

In the past, using several managed object contexts was not easy to manage; you had to create instances of NSManagedObjectContext using the correct queues yourself. Luckily, NSPersistentContainer helps to make complex setups a lot more manageable. If you want to import data on a background task, you can obtain a managed object context by calling newBackgroundContext() on the persistent container. Alternatively, you can call performBackgroundTask on the persistent container and pass it a closure with the processing you want to do in the background.

One important thing to understand about Core Data, background tasks, and multithreading is that you must always use a managed object context on the same thread it was created on. Consider the following example:

let backgroundQueue = DispatchQueue(label: "backgroundQueue")  
let backgroundContext = persistentContainer.newBackgroundContext()  
backgroundQueue.async {  
  let results = try? backgroundContext.fetch(someRequest)  

  for result in results {  
    // use result  
  }  
}

The behavior of this code can cause you a couple of headaches. The background context was created on a different queue than the one it's used it on. It's always best to make sure to use a managed object context on the same queue it was created on by using the perform(_:) method of NSManagedObject. More importantly, you must also make sure to use the managed objects you retrieve on the same queue that the managed object context belongs to.

Often, you'll find that it's best to fetch data on the main queue using the viewContext persistent containers. Storing data can be delegated to background contexts if needed. If you do this, you must make sure that the background context is a child context of the main context. When this relationship is defined between the two contexts, your main context will automatically receive updates when the background context is persisted. This is quite convenient because it removes a lot of manual maintenance, which keeps your contexts in sync. Luckily, the persistent container takes care of this for you.

When you find that your app requires a setup with multiple managed object contexts, it's essential to keep the rules mentioned in this section in mind. Bugs related to using managed objects or managed object contexts in the wrong places are often tedious to debug and hard to discover. When implemented carefully, complex setups with multiple managed object contexts can increase your application's performance and flexibility.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset