Quantcast
Channel: Core Data – Michael Tsai
Viewing all articles
Browse latest Browse all 217

Persistent History Tracking in Core Data

$
0
0

Steffen Ryll:

At WWDC ’17, Apple introduced a number of new Core Data features, one of which is Persistent History Tracking or NSPersistentHistory. But as of the time of writing, its API is still undocumented. Thus, the only real reference is the What’s New in Core Data WWDC session.

Since Persistent History Tracking makes sharing an NSPersistentStore across multiple processes and is one of my favorite new Core Data features, it is unfortunate that it mostly seems to fall of the radar.

The purpose of this post is to give a real-world example on how to use it and what makes it so great.

That was written a year and a half ago, and NSPersistentHistory remains a really cool feature that’s under-discussed and under-documented. Some resources I’ve found are:

Here are some things I figured out by exploring:

  • The history is stored directly in the same SQLite database(s) as the persistent store.
  • It uses tables that look kind of like Core Data tables, only with a different prefix.
  • But you couldn’t create them yourself using Core Data, since the same column can store the primary key for different types of entities (you would think NSObjectIDAttributeType could do that, but it actually can’t be used in stores), and likewise for the columns that store the tombstone values.
  • The tables are updated using SQLite triggers, which are again not directly exposed in Core Data (though this year’s new derived attributes also use them).
  • The triggers are fired for all database changes, so unlike the managed object context’s change tracking, they also work for batch updates and deletions (and, presumably, the forthcoming batch insertions).
  • The tables look very compact, with repeated string values interned and the list of modified columns stored as a bit vector.
  • Core Data automatically updates the schema of the history tracking tables when you do a migration.
  • Enabling history tracking does not change the version of your model. But, in practice, you’ll get incorrect results if you don’t enable it consistently.
  • Setting an attribute to be preserved after deletion (i.e. for the tombstone) does change the model’s version hash, however.
  • There’s no public API to set this flag on an attribute in the model, only a checkbox in Xcode. However, you can use key-value coding to set or query NSPropertyDescription.preserveValueOnDeletionInPersistentHistory.
  • So, overall, it seems tricky to use persistent history on a store that will be shared with OS versions that don’t support history tracking. You might have to roll your own in that case.
  • Querying and pruning the history works as you would expect.
  • The NSPersistentHistoryTransaction.objectIDNotification() does not generate a NSManagedObjectContextDidSaveNotification, but rather a private NSManagedObjectContextDidSaveObjectIDsNotification notification.
  • Rather than containing full objects under keys like NSUpdatedObjectsKey, it contains object IDs under keys like updated_objectIDs. This is a bit unexpected, because NSManagedObjectContext is already documented to support NSManagedObjectID or NSURL objects under the NSUpdatedObjectsKey key.
  • In any case, you get IDs because it isn’t storing the changed values. Instead, when merging, it fetches the latest values from the store.
  • This makes sense given the data model, but it means that, perhaps counterintuitively, merging will update all the attributes, not just those those changed in the transaction that generated the notification. And they’ll be updated to the current values, which may be much newer than the ones at the time of the transaction. This is not version control, just a way to see what has changed.

Viewing all articles
Browse latest Browse all 217

Latest Images

Trending Articles



Latest Images