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.