Mastering In CoreData (Part 17 Multithreading Concurrency Strategy Context UndoManager)

Core Data

This part is the continuation of the previous part. It is mandatory to look the temporary problem that we solved using parent child strategy. Now in this part we are going to solve this problem using undo manager . To know what is the temporary change problem please refer to previous part

In part 2 we said

Managed Object Context (MOC)

Managed Object Context provides Caching, Change tracking, Lazy loading, Redo, Undo and validation features

Undo Manager

UndoManager provides a simple way to add undo/redo functionality to your managed Object Context. It’s an Instance property of the managed object context.

Download the starter project or delete the application if you follow the tutorials. First comment out these lines as shown in Figure 1.

Figure 1

Understand Undo Manager from Flow Diagram

As you can see in Figure 2 we performed number of tasks to understand how undo manager works

  1. First, we start/begin undo group to keep track of the changes we will perform. At this point undo manager start tracking changes
  2. Added User 1 to the managed object context and put it‘s reference to undo stack
  3. Added User 2 to the managed object context and put it‘s reference to undo stack
  4. Ended undo group (It’s very important otherwise application will crash)
  5. Performed context.undo to undo changes
  6. As you can see User 1 and User 2 now deleted and moved it ot the redo stack
  7. Performing redo User 1 and User 2 now appear
Figure 2

As you can see in Figure 3 we proved flow diagram theory into code

  1. Created undoManager instance property of Managed Object Context. By default, in iOS it’s value is nil
  2. By calling beginUndoGrouping , we start tracking objects and group into the undo stack
  3. Added two users object into the managed object context
  4. endUndoGrouping will end this group. This is very important
  5. Finally we looks into the logs by doing undo and redo operation

As you can see no User object was printed after undo operation . By doing redo two user object printed on the console

Note: First beginUndoGrouping increment grouping level to 2 .

Figure 3

Nested Undo Group

Performs the undo operations in the last undo group

As you can see in Figure 4. undoNestedGroup group undo last group which was when User 2 was added. As you can see we added User on first undo group and User 2 on second or last undo group. By performing undoNestedGroup it will undo last undo group which was where User2 was added. Now first undo group become the last after calling undoNestedGroup again it will delete User1 as well as shown in the Figure 4

Figure 4

As you can see in Figure 5 we proved it using code . Performing undo Nested group undo last group.

Figure 5

There are number of things you should know

undo → Closes the top-level undo group if necessary and invokes undoNestedGroup().

undoNestedGroup → Performs the undo operations in the last undo group (whether top-level or nested), recording the operations on the redo stack as a single group

levelsOfUndo: Int →The maximum number of top-level undo groups the receiver holds.

beginUndoGrouping → Marks the beginning of an undo group.

endUndoGrouping → Marks the end of an undo group.

removeAllActions → Clears the undo and redo stacks and re-enables the receiver.

Solve Temporary Change Problem In Application Using Undo Manager

First delete the application and uncomment viewDidLoad and viewWillAppear method as shown in Figure 6. To understand the application, project structure and the problem we are going to solve referred to previous part then come again. In previous we solved the temporary changes problem using parent-child strategy , now we are going to solve it using context undoManger features.

Figure 6

As you can see in Figure 7 we did lot of things to setup undoManager

  1. Created custom back button to get the action of back event
  2. Fetched User data from main singleton Managed Object Context and that directly populating view . Editing in information will update this context objects as well.
  3. Before fetched we begin undoManager to track temporary changes
Figure 7

Now when user tap on back button we did a couple of things as shown in Figure 8

  1. First we ended the undo group. It’s very important we need to call it before calling undo method
  2. Finally we discard changes by calling undo method it will discard all the changes that was done in the context from the beginning to end of the undo group
Figure 8

Run the application and run the flow which caused temporary changes was saving in database, now the problem is solved using undoManager.

RollBack Managed Object Context

Removes everything from the undo stack, discards all insertions and deletions, and restores updated objects to their last committed values

Understand Using Flow Diagram

As you can see in Figure 9 after calling rollback it discarded all temporary changes in the context and moved their state to last committed value which is the same state as of the persistent store. To illustrate this with example first delete the application and comment out viewDidLoad and viewwillAppear method on ViewController.swift

Figure 9

As you can see in Figure 10 we did number of things

  1. First, we created User1 and save it to the persistent store by calling save method on the context
  2. Next User 2 and User 3 created on context only. These are the users not in the persistent store yet
  3. By calling rollback it discarded all the temporary changes in the context. As you can see in the logs User 2 and User 3 was deleted since it was not in the persistent store as we said earlier rollback move the context to the last committed value which means the state of the persistent store
  4. One thing remembered User 1 referenced will not change if you are using in existing UI application will not crash. Since it will not refresh data from a persistent store it’s referenced remain the same . (Important)
Figure 10

Reset Managed Object Context

Returns the context to its base state

Understand Using Flow Diagram

As you can see in the Figure 11 it performs the same thing as the rollback did. We first saved User1 into the persistent store after that we cached User1 in Managed Object Context . Then we temporarily added User2 and User3 which was not in the persistent store yet. After that we called reset method on the context and it did the same thing as rollback did,but there was a slightly difference.It again fetched User1 from persistent store that’s why it’s address was changed whereas in rollback User1 address was the same.

Figure 11

As you can see in Figure 12 t we did number of things and delete the application

  1. First, we created User1 and save it to the persistent store by calling save method on the context
  2. Next User 2 and User 3 was created on context only. This was the users not in the persistent store yet
  3. By calling reset it discarded all the temporary changes in the context. As you can see in the logs User 2 and User 3 were deleted since it was not in the persistent store
  4. One thing remembered User 1 referenced has changed and if you are using in existing UI application will crash. I used rollback screenshot since there is a minor difference. Since it will refreshed data from a persistent store it’s referenced will change.
Figure 12

Note: All the receiver’s managed objects are “forgotten.” If you use this method, you should ensure that you also discard references to any managed objects fetched using the receiver, since they will be invalid afterwards.

Difference Between Reset and RollBack

Delete the application first

Reset : As you can see reference change and data became faulty also. Since it gets data from a persistent store as shown in Figure 13.

Figure 13

Delete the application first

Rollback : Reference is the same and since it didn’t delete cache data. The data still presents in the cache as shown in Figure 14

Figure 14

Useful Links

https://www.raywenderlich.com/5229-undomanager-tutorial-how-to-implement-with-swift-value-types

Senior iOS Engineer | HungerStation | Delivery Hero