CoreData: CRUD With Concurrency In Swift - Part 2
Do you have performance issues with your CoreData implementation because you’re blocking the main thread with some computations? This series can help you to solve your problems and improve the user experience of your App. Second Part: Read.
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.
To fetch the data asynchronously in a background queue, CoreData provides the object
We can create this object passing a
NSFetchRequest argument in its constructor and then executing it thanks to the
execute method of
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:
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.
Since we are using a
NSFetchRequest to create a
NSAsynchronousFetchRequest, we can also set to
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
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
NSAsynchronousFetchRequest allows us also to receive notifications of the fetch progress. It’s an useful feature if we want to show the user some information 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 details in the official documentation
In this example, we observe
completedUnitCount just for the sake of explanation, we can observer any
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!