Introduction

This is the second part of the series CoreData: CRUD With Concurrency In Swift: READ.

If you didn’t read the first part, I would suggest you to read it since I introduced this series.

In this article, we are going to learn how to read some data with CoreData, using background queues—to avoid blocking the main queue.

Happy Reading!

Contents

NSAsynchronousFetchRequest

To fetch the data asynchronously in a background queue, CoreData provides the object NSAsynchronousFetchRequest.

We can create this object passing a NSFetchRequest argument in its constructor and then executing it thanks to the execute method of NSManagedObjectContext.

Moreover, the constructor of NSAsynchronousFetchRequest has also a closure parameter, which is called when the fetch finishes. This closure has also a fetch result object as parameter–NSAsynchronousFetchResult–to retrieve the data.

To perform this asynchronous fetch in a background queue, we must call the execute method using a private context. As we saw in the first part of this series, we have two ways to do it:

iOS 8+

iOS 10+

Once we have our private context, we are ready to perform our fetch:

As we can see in the example above, we can retrieve the result of the fetch inside the completion closure using the property finalResult of the object passed as parameter of this closure.

Note

Since we are using a NSFetchRequest to create a NSAsynchronousFetchRequest, we can also set to fetchRequest a NSPredicate to add a specific condition to our query and/or a NSSortDescriptor to order the query result.

Different Queues Communication

Since we’re fetching using a private context, the completion closure will be executed in a background queue. It means that, if we want to use the data in the main queue—for tasks like updating the UI—we must pass the data from background to the main queue. To achieve it, we can use DispatchQueue.main.async {}.

When we pass NSManagedObject between different queues, we should pay attention.

As we can read in the official documentation here:

NSManagedObject instances are not intended to be passed between queues. Doing so can result in corruption of the data and termination of the application. When it is necessary to hand off a managed object reference from one queue to another, it must be done through NSManagedObjectID instances.

You retrieve the managed object ID of a managed object by calling the objectID method on the NSManagedObject instance.

It means that, if we want to use the data in the main queue, we should update our dispatch queue like this:

For the lovers of higher-order functions, we can write the example above in this way:

Remember to use the keyword lazy. In this way, the chain of higher-order functions will be combined in one function, interating the array just once. If we don’t use lazy, we would iterate the array twice since we are using two flatMap.

More…

NSAsynchronousFetchRequest allows us also to receive notifications of the fetch progress. It’s an useful feature if we want to show the user some informations about the fetching like a progress HUD.

If we want to receive the notification of the progress, we can set a KVO observer like in this example:

Then, we can use the KVO callback to read the new progress data:

If you’re wondering why we have to create a new Progess object and set it as default one, the answer is that it’s the way to add a child progress—the one of NSPersistentStoreAsynchronousResult—in the current thread. You can find more datails in the official documentation

In this example, we observe completedUnitCount just for the sake of explanation, we can observer any Progess property.

Conclusion

We’ve just finished also our second adventure in the CoreData concurrency world. In the next article, we’ll see how to update the data in a background queue. Stay tuned!