Mastering In CoreData (Part 13 Multithreading Concurrency Strategy Notifications)

Core Data

There are two popular strategies that Core Data supports, notifications and parent-child managed object contexts. In this part we will look Notifications only .This strategy is not recommended by apple so we will not doing in depth.

Types Of Notifications

Managed Object Context posts three types of notifications to notify objects of changes taking place in a Managed Object Context

NSManagedObjectContextObjectsDidChangeNotification: This notification is posted when one of the managed objects of the managed object context has changed

NSManagedObjectContextWillSaveNotification: This notification is posted before the Managed Object Context performs a save operation

NSManagedObjectContextDidSaveNotification: This notification is posted after the managed object context performs a save operation

Note: These notification will only post when you call save() method on the context. When you call save() method WillSaveNotification and NDidSaveNotification notifications will surely call and the DidChangeNotification only calls when you actually done some changes in the context.

When a Managed Object Context save its changes to a Persistent Store, via the persistent store coordinator, other managed object contexts may want to know about those changes. This is very easy to do and it’s even easier to include or merge the changes into another managed object context.

Note : These notification will not fire if you are doing NSBatchUpdateRequest/NSBatchDeleteRequest (Ignore for now )

Handling Notifications

Download the starter project here and if you you have already delete the application first

We can observe these notifications by adding an observer to NotificationCenter As shown in Figure 1

Figure 1

As you can see in Figure 2 we handled DidChangeNotification only . The notifications are just half of the whole story. As you can see all observers method are passed by notification object. Notification object has a userInfo instance property that holds all the information in a Dictionary. These are all the keys that are used to retrieve the changed data

NSUpdatedObjectsKey key contains all the NSManagedObject updated.

NSInsertedObjectsKey key contains all the NSManagedObjectinserted.

NSDeletedObjectsKey key contains all the NSManagedObject deleted.

NSRefreshedObjectsKey key contains all the NSManagedObject refreshed.

Figure 2

Insert Case

As you can see we inserted User object in Figure 3 . Notification will fire when save() method executed

Figure 3

As you can see in Figure 4 since we inserted object in Figure 3 which means there is a change in the context first DidChangeNotification will fire and we handled this that’s why in the console it is printed that we inserted object.

After that WillSaveNotification and DidSaveNotification notification will fire sequentially and since we didn’t do anything in their selector method nothing will going to happen. As shown in Figure 4 User that we inserted in Figure 3 is printed on the console .

Figure 4

Update case

As shown in Figure 5 we fetched the User object we just inserted in previous section and update it’s value when we call save() method Notification handler printed the Updated value. We accomplished this by doing following actions

  • Refer to persistentContainer from appdelegate singleton object
  • Create/Access the singleton managed object context from persistentContainer
  • Added Managed Object Context observers to listen to events of the context
  • Fetched User we just inserted from persistent store and updated it’s firstName and secondName properties as shown in Figure 5
  • Performed commit to persistent store using save method in the main context
  • Notification DidChangeNotification method printed the updated value in the console
  • After that WillSaveNotification and DidSaveNotification notifications will fire sequentially and since we didn’t do anything in their selector method nothing will going to happen
Figure 5

We will not do delete. You can trust it will work. Now the question is we notified what is updated, inserted and deleted but how can we merged or update other context as well . In the next section we will going to do this

Merges Changes to Another Context

As we saw in part 12 we encountered concurrency problem in which one context was doing some heavy task in the background thread and other is dealing with UI related work but both are unaware of the work status Weather it is done or not and we saw that one context saves data into the persistent store and other used older value which caused a problem. So in this section we will look how notification can solve this problem and merged updated value to other context when one is done with their task. In short how one context update other context with the changes that is done by that.

Let’s suppose we have two managed Object Context we called Managed Object Context A and Managed Object Context B both request User data from the persistent store as shown in Figure 6. User Entity has firstName and secondName properties.

Managed Object Context B private context that is processing server data

Managed Object Context A representing UI data main Thread

Figure 6

As shown in Figure 7 Managed Object Context B updated firstName value from the data that comes from server and pushed that changes to persistent Store Coordinator to Persistent Store using save method on the context. Managed Object Context A doesn’t know that changes still and have older value which is a problem

Figure 7

As shown in figure 8 if we are handling notification as discussed in previous section we can observed to the NSManagedObjectContextDidSave notification now when save action was done NSManagedObjectContextDidSave selector will be executed and we can call mergeChanges method which will update ManagedObjectContextA so using notifications of the context we can solve this problem.

Now both context will have same state. There can be chances that while merging conflict occurs and we will discuss these conflict later.

Figure 8

Now let's dive into the coding parts and proved it using code but before start first delete the application. We added user object and save it to the persistent store as shown in in Figure 7 .

Figure 7

When private context update value we just inserted , using notification we merged that changes to main context as well and you can see on the console in the Figure 9 . We accomplished this after performing number of tasks

  1. Added NSManagedObjectContextDidSave observer to listen to the post save event on the private context
  2. Fetched User object on private context and updated firstName value in that context. Note: Main Context is unaware of the changes done by the private context
  3. Called save method to pushed updated User to the persistent store
  4. Printed child context User object on the console updated value was reflecting
  5. When save method finished it will post notification we observed which is NSManagedObjectContextDidSave and called selector method to perform action we defined contextDidSave(_ notification: Notification)
  6. contextDidSave(_ notification: Notification) we merged private context changes into the main context using mergeChanges method available in the context
  7. Now main context have updated value as shown in the console in Figure 8. Printed updated value

Note: When we call mergeChanges method there might be a chance that conflict occurs, for that we need to create merge policy and we will discuss this in the upcoming parts .

Figure 8

Disadvantages

  1. Complex code →Increases bugs
  2. Manually Synchronization
  3. Large amount of code
  4. Cross traffic between Managed Object Context

Summary

In this part 13 we solved the concurrency problem using Notification that Core data provides

What Next?

In the next part we will look how to solve the concurrency problem using Parent Child Concurrency Strategy that Core data Provides

Useful Links

https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreData/Concurrency.html

https://medium.com/shakuro/introduction-to-ios-concurrency-a5db1cf18fa6

https://cocoacasts.com/swift-and-cocoa-fundamentals-threads-queues-and-concurrency
https://developer.apple.com/documentation/coredata/using_core_data_in_the_background

https://developer.apple.com/documentation/coredata/nsmanagedobjectcontext

https://medium.com/@marcosantadev/core-data-notifications-with-swift-acc8232a674e

https://marcosantadev.com/core-data-notification-swift/

https://www.youtube.com/watch?v=_QolYhiKWvU

Senior iOS Engineer | HungerStation | Delivery Hero