BLACK FRIDAY: Save 50% on all books and bundles! >>

How to configure Core Data to work with SwiftUI

Paul Hudson    @twostraws   

Updated for Xcode 12.0

If you create a new project and check both SwiftUI and Core Data, Xcode does a pretty good job of getting you towards a working configuration. Specifically, it:

  1. Creates an empty YourProjectName.xcdatamodeld model file.
  2. Adds a persistentContainer lazy property to the app delegate, that loads the model file into a container.
  3. Adds a saveContext() method to the app delegate that will check for changes and save if needed.
  4. Injects the context into the initial content view’s environment using the managedObjectContext key.
  5. Calls that saveContext() method from the scene delegate’s sceneDidEnterBackground() method, ensuring that Core Data updates are flushed when the scene moves to the background.

That provides for us the complete ability to use Core Data fetch requests from within SwiftUI, although we still need to add some example data to work with.

However, if you didn’t use the Core Data template or you’re just curious what the Core Data template does for us, it’s worth covering briefly the steps it takes to set up support in your apps. I’m also going to provide you with some sample data to work with so you can try out subsequent chapters in this book.

The first step is to create a Core Data model by press Cmd+N to make a new file, then choosing Data Model. The name of this model matters, because it will be used in your code shortly. Once you have your model you can go ahead and create any entities you want to use in your app.

Second, your need to load your Core Data model into the app in your app delegate, handling any errors as appropriate. Something like this in AppDelegate.swift ought to do the trick:

lazy var persistentContainer: NSPersistentContainer = {
    let container = NSPersistentContainer(name: "CoreDataModelNameHere")
    container.loadPersistentStores { description, error in
        if let error = error {
            // Add your error UI here
    return container

Third, add a saveContext() method to your app delegate so that it checks whether the context has changes and commits them if needed.

func saveContext () {
    let context = persistentContainer.viewContext
    if context.hasChanges {
        do {
        } catch {
            // Show the error here

Fourth, you need to inject the managed object context for your Core Data container into the SwiftUI environment. As far as I can see there is no beautiful way of doing this, and the code Apple uses will probably cause some folks to raise their eyebrows.

To use Apple’s code, open your SceneDelegate.swift file, look for where you create your initial ContentView instance, then modify it to this:

let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let contentView = ContentView().environment(\.managedObjectContext, context)

Yes, that force casts the application delegate to AppDelegate, but realistically the best alternative is something like this:

guard let context = (UIApplication.shared.delegate as? AppDelegate)?.persistentContainer.viewContext else {
    fatalError("Unable to read managed object context.")

That will still crash your code if the typecast fails, but at least it gives us the chance to provide a descriptive error.

Finally, you should make your scenes trigger a Core Data save when they move to the background:

func sceneDidEnterBackground(_ scene: UIScene) {
    (UIApplication.shared.delegate as? AppDelegate)?.saveContext()

Now, because Core Data requires some sort of configuration to get meaningful results all the chapters in this Core Data section use a shared configuration that I won’t keep on repeating.

First, make sure you create a new Single View App that enables both SwiftUI and Core Data support, or a Single View App without Core Data that uses the instructions above to retrofit support.

Now open your xcdatamodeld file and create an entity called ProgrammingLanguage that has two string attributes: “name” and “creator”. Obviously you don’t need to have exactly this entity and attribute collection, so just mentally replace my examples with your own Core Data setup as you go.

Finally, in the data model inspector please change Codegen to be “Class Definition” – this will generate a Language class for us that SwiftUI can work with.

Important: those instructions matter!

To avoid confusion, I want to repeat that the instructions above are important for setting up a useful Core Data environment for SwiftUI. All subsequent Core Data chapters assume you have followed the instructions above.

Save 50% in my Black Friday sale.

Sponsor Hacking with Swift and reach the world's largest Swift community!

Similar solutions…

Buy Pro Swift Buy Swift Design Patterns Buy Testing Swift Buy Hacking with iOS Buy Swift Coding Challenges Buy Swift on Sundays Volume One Buy Server-Side Swift (Vapor Edition) Buy Advanced iOS Volume One Buy Advanced iOS Volume Two Buy Advanced iOS Volume Three Buy Hacking with watchOS Buy Hacking with tvOS Buy Hacking with macOS Buy Dive Into SpriteKit Buy Swift in Sixty Seconds Buy Objective-C for Swift Developers Buy Server-Side Swift (Kitura Edition) Buy Beyond Code

Was this page useful? Let us know!

Average rating: 4.1/5

Link copied to your pasteboard.