{"id":40349,"date":"2023-08-15T15:36:18","date_gmt":"2023-08-15T19:36:18","guid":{"rendered":"https:\/\/mjtsai.com\/blog\/?p=40349"},"modified":"2023-08-15T16:08:52","modified_gmt":"2023-08-15T20:08:52","slug":"turning-off-core-data-persistent-history-tracking","status":"publish","type":"post","link":"https:\/\/mjtsai.com\/blog\/2023\/08\/15\/turning-off-core-data-persistent-history-tracking\/","title":{"rendered":"Turning Off Core Data Persistent History Tracking"},"content":{"rendered":"<p>It&rsquo;s not documented, but Core Data doesn&rsquo;t like you to turn off persistent history tracking once it&rsquo;s been enabled for a store. If you set <code>NSPersistentHistoryTrackingKey<\/code> to <code>false<\/code> after it had been set to <code>true<\/code>, opening the store will seem to succeed, but it will <a href=\"https:\/\/stackoverflow.com\/questions\/69131577\/nsmigrationmanager-migratestore-with-nspersistenthistorytrackingkey\">log<\/a> <a href=\"https:\/\/developer.apple.com\/forums\/thread\/118924\">an<\/a> <a href=\"https:\/\/developer.apple.com\/forums\/thread\/129745\">error<\/a> like:<\/p>\n<pre>Store opened without NSPersistentHistoryTrackingKey but previously had been opened with NSPersistentHistoryTrackingKey - Forcing into Read Only mode store at<\/pre>\n<p>No error is reported to your code, although you can check whether <code>store.isReadOnly<\/code> matches what you passed for <code>NSReadOnlyPersistentStoreOption<\/code>. If you fail to notice this, your app is likely to crash at some point. For example, the <code>NSPersistentStoreCoordinator.setMetadata(_:for:)<\/code> method will raise an <code>NSInvalidArgumentException<\/code>, which cannot be caught in Swift.<\/p>\n<p>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&mdash;which ended up not being an unexpected writer but rather a bug in Core Data&rsquo;s uniqueness constraint conflict resolution. I no longer needed history tracking for that store and wanted to avoid the associated performance cost.<\/p>\n<p>It turns out that you <em>can<\/em> turn off history tracking if you first delete the history. So, I can open the store with <code>NSPersistentHistoryTrackingKey<\/code> set to <code>true<\/code>, then execute this request:<\/p>\n<pre>let request = NSPersistentHistoryChangeRequest.deleteHistory(before: .distantFuture)<\/pre>\n<p>Internally, this seems to only do a batch delete on the <code>ACHANGE<\/code> and <code>ATRANSACTION<\/code> tables. It does not actually clear out the interned strings in <code>ATRANSACTIONSTRING<\/code> 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 <code>NSPersistentHistoryTrackingKey<\/code> set to <code>false<\/code>.<\/p>\n<p>Going forward, I will add a key to the store&rsquo;s metadata to record whether it was last opened using <code>NSPersistentHistoryTrackingKey<\/code>. When loading the store, if the key is <code>true<\/code>, I know to remove the history and can avoid logging the error. If it&rsquo;s <code>false<\/code>, I know that the store can be safely opened without adding the history tracking tables.<\/p>\n\n<p>Previously:<\/p>\n<ul>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2019\/08\/21\/persistent-history-tracking-in-core-data\/\">Persistent History Tracking in Core Data<\/a><\/li>\n<\/ul>","protected":false},"excerpt":{"rendered":"<p>It&rsquo;s not documented, but Core Data doesn&rsquo;t like you to turn off persistent history tracking once it&rsquo;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 [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"apple_news_api_created_at":"2023-08-15T19:36:21Z","apple_news_api_id":"bf561772-c7da-474d-8115-bbb24d27e059","apple_news_api_modified_at":"2023-08-15T20:08:55Z","apple_news_api_revision":"AAAAAAAAAAAAAAAAAAAAAQ==","apple_news_api_share_url":"https:\/\/apple.news\/Av1YXcsfaR02BFbuyTSfgWQ","apple_news_coverimage":0,"apple_news_coverimage_caption":"","apple_news_is_hidden":false,"apple_news_is_paid":false,"apple_news_is_preview":false,"apple_news_is_sponsored":false,"apple_news_maturity_rating":"","apple_news_metadata":"\"\"","apple_news_pullquote":"","apple_news_pullquote_position":"","apple_news_slug":"","apple_news_sections":"\"\"","apple_news_suppress_video_url":false,"apple_news_use_image_component":false,"footnotes":""},"categories":[4],"tags":[109,30,2223,71,901],"class_list":["post-40349","post","type-post","status-publish","format-standard","hentry","category-programming-category","tag-coredata","tag-mac","tag-macos-13-ventura","tag-programming","tag-swift-programming-language"],"apple_news_notices":[],"_links":{"self":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/40349","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/comments?post=40349"}],"version-history":[{"count":3,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/40349\/revisions"}],"predecessor-version":[{"id":40356,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/40349\/revisions\/40356"}],"wp:attachment":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/media?parent=40349"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/categories?post=40349"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/tags?post=40349"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}