NEW: Nominations are now open for the 2019 Swift Community Awards! >>

How to configure Core Data to work with SwiftUI

Paul Hudson    @twostraws   

Fully updated for Xcode 11.1

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 {
            try context.save()
        } 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 20% ON iOS CONF SG The largest iOS conference in Southeast Asia is back in Singapore for the 5th time in January 2020, now with two days of workshops plus two days of talks on SwiftUI, Combine, GraphQL, and more! Save a massive 20% on your tickets by clicking on this link.

Similar solutions…

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

Was this page useful? Let us know!

Average rating: 4.0/5