Core Data received an important update during this year's WWDC. We already explored the addition the of the NSPersistentContainer
class and Xcode's improved support for Core Data. But there are several more subtle additions and enhancements worth exploring, such as the NSPersistentStoreDescription
class. That is the focus of this tutorial.
What Is It
As the name of the class suggests, the NSPersistentStoreDescription
class encapsulates the information and configuration to add a persistent store to the persistent store coordinator. In other words, it describes a persistent store.
The NSPersistentStoreDescription
class isn't very useful on its own. The NSPersistentStoreCoordinator
class also defines a new method, addPersistentStore(with:completionHandler:)
. This method accepts two arguments:
- an instance of the
NSPersistentStoreDescription
class - a completion handler of type
(NSPersistentStoreDescription, Error?) -> ()
Adding a Persistent Store
Adding a persistent store to the persistent store coordinator looks something like this. This looks familiar. Right?
// Helper
let persistentStoreURL = self.persistentStoreURL
do {
let options = [ NSMigratePersistentStoresAutomaticallyOption : true, NSInferMappingModelAutomaticallyOption : true ]
try persistentStoreCoordinator.addPersistentStore(ofType: NSSQLiteStoreType, configurationName: nil, at: persistentStoreURL, options: options)
} catch {
let addPersistentStoreError = error as NSError
print("Unable to Add Persistent Store")
print("\(addPersistentStoreError.localizedDescription)")
}
To add the persistent store, we invoke addPersistentStore(ofType:configurationName:at:options:)
on the persistent store coordinator. The first argument is the type of the persistent store, the third argument is its location, and the last argument is a dictionary of options.
In the example, we define two options. We instruct the persistent store coordinator to automatically migrate the persistent store if necessary and it should also infer the mapping model for the migration. These options are very common.
Using the NSPersistentStoreDescription Class
The above example looks fine, but we can do better by using the NSPersistentStoreDescription
class. Take a look at the updated example below.
// Helper
let persistentStoreURL = self.persistentStoreURL
// Create Persistent Store Description
let persistentStoreDescription = NSPersistentStoreDescription(url: persistentStoreURL)
// Configure Persistent Store Description
persistentStoreDescription.type = NSSQLiteStoreType
persistentStoreDescription.shouldMigrateStoreAutomatically = true
persistentStoreDescription.shouldInferMappingModelAutomatically = true
persistentStoreCoordinator.addPersistentStore(with: persistentStoreDescription, completionHandler: { (persistentStoreDescription, error) in
if let error = error {
print("Unable to Add Persistent Store")
print("\(error.localizedDescription)")
}
})
There are several important differences. The first thing you probably notice is that the NSPersistentStoreDescription
class neatly encapsulates the metadata of the persistent store.
We initialize an instance of the class by invoking init(url:)
, passing in the location of the persistent store. We then configure the persistent store description by setting the type of the store to NSSQLiteStoreType
.
The options we defined earlier are properties of the NSPersistentStoreDescription
class, shouldMigrateStoreAutomatically
and shouldInferMappingModelAutomatically
. Even though we explicitly set the value of these properties to true
, this isn't necessary since both properties default to true
.
To add the persistent store to the persistent store coordinator, we invoke addPersistentStore(with:completionHandler:)
, passing in the persistent store description and a completion handler. This method is not throwing. To find out if adding the persistent store was successful, we inspect the value of the error
parameter of the completion handler.
The completion handler defines two parameters, the persistent store description that was used to add the persistent store and an optional error object.
persistentStoreCoordinator.addPersistentStore(with: persistentStoreDescription, completionHandler: { (persistentStoreDescription, error) in
if let error = error {
print("Unable to Add Persistent Store")
print("\(error.localizedDescription)")
}
})
The NSPersistentStoreDescription
class defines a property, shouldAddStoreAsynchronously
, that determines how the persistent store is added to the persistent store coordinator, synchronously or asynchronously. By default, a persistent store is added synchronously on the calling thread.
Flexibility and Versatility
The NSPersistentStoreDescription
class defines several other interesting properties, such as isReadOnly
and timeout
. You can also define store and migration options using the setOption(_:forKey:)
method.
The NSPersistentStoreDescription
class is another welcome addition to the Core Data framework. The class works very well in combination with the NSPersistentContainer
class. The latter defines the persistentStoreDescriptions
property, which is of type [NSPersistentStoreDescription]
. This makes it very easy to add one or more persistent stores to the persistent store coordinator. You set the persistentStoreDescriptions
property and invoke loadPersistentStores(completionHandler:)
on the persistent container.