Tuesday, August 15, 2023

Turning Off Core Data Persistent History Tracking

It’s not documented, but Core Data doesn’t like you to turn off persistent history tracking once it’s been enabled for a store. If you set NSPersistentHistoryTrackingKey to false after it had been set to true, opening the store will seem to succeed, but it will log an error like:

Store opened without NSPersistentHistoryTrackingKey but previously had been opened with NSPersistentHistoryTrackingKey - Forcing into Read Only mode store at

No error is reported to your code, although you can check whether store.isReadOnly matches what you passed for NSReadOnlyPersistentStoreOption. If you fail to notice this, your app is likely to crash at some point. For example, the NSPersistentStoreCoordinator.setMetadata(_:for:) method will raise an NSInvalidArgumentException, which cannot be caught in Swift.

This makes sense in that, if you could turn off history tracking and later turn it back on, the history would be there but would have a gap, which could lead to bugs. In my case, though, I had only turned on history tracking to track down a bug—which ended up not being an unexpected writer but rather a bug in Core Data’s uniqueness constraint conflict resolution. I no longer needed history tracking for that store and wanted to avoid the associated performance cost.

It turns out that you can turn off history tracking if you first delete the history. So, I can open the store with NSPersistentHistoryTrackingKey set to true, then execute this request:

let request = NSPersistentHistoryChangeRequest.deleteHistory(before: .distantFuture)

Internally, this seems to only do a batch delete on the ACHANGE and ATRANSACTION tables. It does not actually clear out the interned strings in ATRANSACTIONSTRING or remove the history tracking tables themselves. But the bulk of the data is gone, and Core Data will let me re-open the store with NSPersistentHistoryTrackingKey set to false.

Going forward, I will add a key to the store’s metadata to record whether it was last opened using NSPersistentHistoryTrackingKey. When loading the store, if the key is true, I know to remove the history and can avoid logging the error. If it’s false, I know that the store can be safely opened without adding the history tracking tables.

Previously:

1 Comment RSS · Twitter · Mastodon

Great!

Leave a Comment