Search code examples
iosswiftcore-data

What problem viewContext.setQueryGenerationFrom is trying to solve in CoreData project which involves transaction history?


I have came across 2 demo CoreData projects, which involves transaction history.

Both are using

viewContext.setQueryGenerationFrom(.current)

when they initialize their CoreData stack.


FireballWatch demo from raywenderlich

The demo is picked from https://www.raywenderlich.com/14958063-modern-efficient-core-data

The author is trying to demonstrate, how to make use of transaction history, to update UI correctly after batch insertion.

However, it isn't clear on what problem viewContext.setQueryGenerationFrom(.current) is trying to solve.

Code : https://github.com/yccheok/FireballWatch_Materials/blob/main/final/FireballWatch/Model/Persistence.swift#L100

Brief explanation of the article https://www.raywenderlich.com/14958063-modern-efficient-core-data doesn't tell much about the idea behind setQueryGenerationFrom.

You are pinning the view context to the most recent transaction in the persistent store with the call to setQueryGenerationFrom(_:). However, because setting query generation is only compatible with an SQLite store, you do so only if inMemory is false.


Synchronizing a Local Store to the Cloud from Apple

The demo is picked from https://developer.apple.com/documentation/coredata/synchronizing_a_local_store_to_the_cloud

It is trying to demonstrate, how to use transaction history, to prevent data duplication after syncing with CloudKit.

However, it is still not clear on what problem viewContext.setQueryGenerationFrom(.current) is trying to solve.

Code: https://github.com/yccheok/SynchronizingALocalStoreToTheCloud/blob/main/CoreDataCloudKitDemo/DataProvider/CoreDataStack.swift#L89

Not much explanation is given behind the idea on setQueryGenerationFrom.


Experiment

No matter whether I have included viewContext.setQueryGenerationFrom(.current), or excluded viewContext.setQueryGenerationFrom(.current) in my CoreData stack, I am having the same observation in both situations.

  • Able to observe UI update immediately, after I save a new NSManagedObject, with context.save called.
  • Able to observe UI update immediately, after I edit an existing NSManagedObject, with context.save called.
  • Able to observe UI update immediately, after I perform batch NSBatchUpdateRequest operation, with mergeChanges called.
  • Able to observe UI update immediately, after I perform batch NSBatchDeleteRequest operation, with mergeChanges called.

There are some good graphical explanation on what is doing by setQueryGenerationFrom

https://cocoacasts.com/what-are-core-data-query-generations

However, I fail to relate it to, what kind of real problem setQueryGenerationFrom is trying to solve.

Does anyone know, what problem viewContext.setQueryGenerationFrom is trying to solve in CoreData project which involves transaction history? Would be appreciate, if there is a solid demo code example, to show what kind of problem is solved by setQueryGenerationFrom. Thank you.


Solution

  • Taking the demo project CoreDataCloudKitDemo, it is to support the case where device1 is editing a post, and device2 deletes it. You can take look for this piece of code:

    // The selected post was changed, and the user isn’t editing it.
    // Show an alert, and go back to the main view to reload everything after the user taps reload.
    let alert = UIAlertController(title: "Core Data CloudKit Alert",
                                  message: "This post has been deleted by a peer!",
                                  preferredStyle: .alert)
    

    With the magic of query generation, we will be able to immediately pop up this alert on the device1 which is editing the post, after device2 device deletes it.

    On the main listing view, there are no issues, as the item will probably just be animated out of the list. The issue is for the details view, what is going to be shown, and what happens if the user edits the value the details view.

    In samples codes, this is usually following

    container.viewContext.automaticallyMergesChangesFromParent = true
    

    As in the details view, usually we will be holding on to an object, and once it is deleted, the object itself should become invalid, and accessing it or the attributes will cause unexpected behaviours.