Guarantee that a context won’t see store changes until you tell it to look.
- Core Data
Query generations give your UI a stable view of data in the database, regardless of changes happening to the store underneath. Whenever you read from a context, you see the same generation, or snapshot, of data until you choose to advance it to a later generation.
Use query generations when you want to isolate your view context from any changes made in the store by background threads in your app, app extensions, CloudKit, or other sources.
Ensure the Correct Type and Mode for the Persistent Store
To use query generations, the persistent store must be an
NSSQLite in write-ahead logging (WAL) journal mode. Core Data creates SQLite stores with WAL mode enabled by default.
Query generations leverage WAL mode to let you query against the historical state of the database. Core Data appends transactions to a
.sqllite-wal file, or journal, in the same directory as the main store file. When your context reads from the journal, it starts at the transaction associated with a specific generation, instead of at the most recent transaction.
To confirm whether a custom store has WAL mode enabled, turn on SQL logging. Choose Product > Scheme > Edit Scheme, choose the Run action, and add the following line under Arguments Passed on Launch.
Run your app, and look for the following output in the console.
If you try to use query generations with a store that’s not an
NSSQLite in WAL journal mode, your contexts gracefully revert to unpinned behavior.
Pin Your View to a Store Generation
By default, contexts are unpinned, and read from the store at the generation of the most recent transaction. Pinned contexts read from the store at the generation of a specific transaction.
To pin a context, call
set, passing an opaque
NSQuery. The context updates to the specified generation lazily on the next read (fetching or faulting) operation.
current generation token to pin the context to the generation corresponding to the most recent store transaction. For example, pass the
current generation token when setting up your stack to pin the view context to the first generation that it fetches.
Alternatively, use the
query from another pinned context to align both contexts to the same generation.
To unpin a context, call
Nested contexts inherit their parent’s generation. They’re implicitly unpinned, but they see data as viewed through the generation of their parent with the addition of their parent’s pending changes.
A generation doesn’t include stores added to the store coordinator after the generation’s creation. Additionally, if you remove a store from the coordinator, do not try to load data from the deleted store into a context.
Update Your View Context to the Current Store Generation
Advance a context to the generation of the most recent transaction, and pin it there, by calling
set and passing the
current token. The context updates to the specified generation lazily on the next read (fetching or faulting) operation.
Alternatively, update a context’s generation by calling any of the following.
Update contexts to the
current generation as soon as a specific generation is no longer needed. Query generations hold a file lock open to maintain the integrity of the journal for the duration of a query generation. Once no contexts refer to a query generation, it expires, and the system can reclaim the journal disk space.
Refresh any managed objects registered to the context after you change the context’s query generation or unpin the context. Managed objects do not automatically refresh, as this behavior may not be desirable and is difficult to revert.
refresh on the context to refresh its existing managed objects.
fetch(_:) on the context to retrieve a fresh set of managed objects matching your request criteria.
The fetch reads the journal from the context’s query generation if pinned, or from the most recent transaction if unpinned.