You may be wondering why we didn't save the note immediately after creating it. That's a fair question. We could have. But why would we? Why would we push the changes of the managed object context to the persistent store every time something changes in the managed object context? That's a waste of resources and it may even impact performance, depending on the complexity of the operation.
A common approach is saving the changes of the managed object context when the application is about to enter the background and before it's about to be terminated by the operating system. This is very easy to implement.
Revisiting the Core Data Manager
Open CoreDataManager.swift and revisit the designated initializer, init(modelName:). We invoke a helper method in the initializer, setupNotificationHandling(). I prefer to keep initializers short and concise hence the helper method.
CoreDataManager.swift
init(modelName: String) {
self.modelName = modelName
setupNotificationHandling()
}
In setupNotificationHandling(), we add the Core Data manager instance as an observer of two notifications sent by the UIApplication singleton:
UIApplicationWillTerminate- and
UIApplicationDidEnterBackground
CoreDataManager.swift
private func setupNotificationHandling() {
let notificationCenter = NotificationCenter.default
notificationCenter.addObserver(self,
selector: #selector(saveChanges(_:)),
name: Notification.Name.UIApplicationWillTerminate,
object: nil)
notificationCenter.addObserver(self,
selector: #selector(saveChanges(_:)),
name: Notification.Name.UIApplicationDidEnterBackground,
object: nil)
}
When the Core Data manager receives one of these notifications, the saveChanges(_:) method is invoked. In this method, we invoke another helper method, saveChanges().
CoreDataManager.swift
@objc func saveChanges(_ notification: Notification) {
saveChanges()
}
Saving Changes
The save operation takes place in the saveChanges() method.
CoreDataManager.swift
private func saveChanges() {
}
We first ask the managed object context if it has changes we need to push to the persistent store. We do this by asking for the value of its hasChanges property. We exit early if no changes need to be pushed to the persistent store.
CoreDataManager.swift
guard managedObjectContext.hasChanges else { return }
If the managed object context has changes we need to push, we invoke save() on the managed object context in a do-catch statement. Remember that save() is a throwing method. If the save operation fails, we print the error to the console.
CoreDataManager.swift
do {
try managedObjectContext.save()
} catch {
print("Unable to Save Managed Object Context")
print("\(error), \(error.localizedDescription)")
}
This is what the implementation of saveChanges() looks like.
CoreDataManager.swift
private func saveChanges() {
guard managedObjectContext.hasChanges else { return }
do {
try managedObjectContext.save()
} catch {
print("Unable to Save Managed Object Context")
print("\(error), \(error.localizedDescription)")
}
}
Because the save operation takes place when the application isn't in the foreground, it isn't useful to notify the user if the save operation failed. However, it doesn't mean that you can ignore any errors that are thrown when something goes wrong. It's recommended to notify the user at some point that a problem occurred.
Build and Run
Let's see if this works. We start with a clean installation of the application and create a new note. We then push the application to the background and inspect the contents of the persistent store.

That seems to work fine. In the next episode, you learn how to fetch the notes from the persistent store and display them in the notes view controller. That's going to be an important and interesting episode.