Mastering In CoreData (Part 13 Multithreading Concurrency Strategy Notifications)
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 )
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
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
NSInsertedObjectsKey key contains all the
NSDeletedObjectsKey key contains all the
NSRefreshedObjectsKey key contains all the
As you can see we inserted User object in Figure 3 . Notification will fire when
save() method executed
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.
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 .
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
secondNameproperties as shown in Figure 5
- Performed commit to persistent store using
savemethod in the main context
DidChangeNotificationmethod printed the updated value in the console
- After that
DidSaveNotificationnotifications will fire sequentially and since we didn’t do anything in their selector method nothing will going to happen
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
Managed Object Context B private context that is processing server data
Managed Object Context A representing UI data main Thread
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
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.
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 .
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
NSManagedObjectContextDidSaveobserver to listen to the post
saveevent on the private context
- Fetched User object on private context and updated
firstNamevalue in that context. Note: Main Context is unaware of the changes done by the private context
savemethod to pushed updated User to the persistent store
- Printed child context User object on the console updated value was reflecting
savemethod finished it will post notification we observed which is
NSManagedObjectContextDidSaveand called selector method to perform action we defined
contextDidSave(_ notification: Notification)
contextDidSave(_ notification: Notification)we merged private context changes into the main context using
mergeChangesmethod available in the context
- Now main context have updated value as shown in the console in Figure 8. Printed updated value
Note: When we call
mergeChangesmethod 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 .
- Complex code →Increases bugs
- Manually Synchronization
- Large amount of code
- Cross traffic between Managed Object Context
In this part 13 we solved the concurrency problem using Notification that Core data provides
In the next part we will look how to solve the concurrency problem using Parent Child Concurrency Strategy that Core data Provides