Core Data: Beyond the Basics

Jul 26 2022 · Swift 5.5, iOS 15, Xcode 13.3.1

Part 1: Fetching & Displaying Launches

02. Displaying Launches

Episode complete

Play next episode

About this episode

Leave a rating/review

See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 01. Introduction Next episode: 03. Sorting Data Using Sort Descriptors
Transcript: 02. Displaying Launches

Now that you know how to save a Launch, the next step is to get those launches out of the persistent store and display them in a list so that you can see when they take place.

Core Data retrieves records from the data store by means of a fetch request. Fetch requests, represented by the class NSFetchRequest, must contain an entity description or name and optionally, a way to sort and filter the results that you get back.

Navigate to RocketLaunch+CoreDataProperties and in the extension of RocketLaunch you’re going to define a fetch request to fetch all the launches in the data store. You don’t need to define the request here but it’s a common convention, since you can house the logic all in one place instead of in views or view controllers.

Instances of NSManagedObject have a class or instance method that returns a generic fetch request. If you navigate to the definition of RocketLaunch and click through to read the interface of NSManagedObject, you’ll see a fetchRequest() declared that returns a value of type NSFetchRequest. You could use this, but in SwiftUI there are property wrappers that make life easier.

Define a static func in the extension of RocketLaunch

static func basicFetchRequest() {}

I’m naming this basicFetchRequest() as opposed to just fetchRequest to avoid having to override the existing fetch request function. Instead of returning an object of type NSFetchRequest we’re going to return an instance of type FetchRequest. This is a generic struct defined in the SwiftUI framework and used as a property wrapper.

You’ll need to import the SwiftUI framework.

import SwiftUI

and then back in the function you can return a FetchRequest that is generic over RocketLaunch. The generic type parameter, RocketLaunch in this case, indicates that the results returned by this fetch request are going to be a series of RocketLaunches.

In the body of the function return an instance of the FetchRequest type. There are several convenience initializers and you’re going to use the one that takes an entity and a sort descriptor.

FetchRequest(entity: , sortDescriptors:) 

The entity is an object of type NSEntityDescription and is the Entity represented by this class. All NSManagedObject subclasses have a class function defined that returns the Entity type of the subclass

FetchRequest(entity: RocketLaunch.entity(), sortDescriptors:[])

You’re going to leave the second argument alone for now. We’ll circle back in just a bit. Now that you have a fetch request, you can wire it up with a SwiftUI view and Core Data handles everything automatically. Navigate to LaunchesView where the mock data is currently set up and define a property that stores the fetch request

let launchesFetchRequest = RocketLaunch.basicFetchRequest()

Next you need to add one more property to the view, one that contains the result of the fetch.

var launches: FetchedResults<RocketLaunch> {

FetchedResults is defined in the SwiftUI framework and is a generic collection type that represents the results of performing a fetch request. What you’ve done here is add an easier way to access this collection by exposing the wrappedValue property on the fetch request.

If you’ve been using SwiftUI and property wrappers for a while now you might be shaking your head at this. The correct, more SwiftUI oriented, way to write this is:

@FetchRequest(entity: RocketLaunch.entity, sortDescriptors: []) var launches: FetchedResults<RocketLaunch>

What I’ve done for now is to split up this logic so that you can see what’s going on under the hood. If you’re comfortable with property wrappers, feel free to write it that way. Later on in this course you’ll switch to using property wrappers.

You can use this collection inside the ForEach view to display the rocket launches. Before you can do that though, you need to update the views. Create a HStack within the ForEach, replace the placeholder text with the name of the launch, and a custom view to denote whether the user has viewed this launch or not:

HStack { 
  LaunchStatusView(isViewed: launch.isViewed)
  Text("\( ?? "")")

Now you need to update the preview for LaunchesView so the canvas renders properly.

let context = PersistenceController.preview.container.viewContext
let newLaunch = RocketLaunch(context: context) = "A really cool launch!"
return LaunchesView()

Remember the preview context that you made when filling out the Persistence.swift file? You’re using it here to take advantage of that in-memory context for your previews.

You still have a little work to do with the ForEach operator. In the definition of the ForEach view remove the range operator and replace it with the launches collection obtained by executing the fetch request.

At the moment the closure is discarding the value that’s passed in. Modify this to pass in the rocket launch value.

ForEach(launches, id: \.self) { launch in 

Now the ForEach is ready to go!

Build and run the app. The launch you created in the last course should be visible (if you didn’t watch that course go ahead and add a new launch now). Great! You have successfully created and saved RocketLaunches and fetched them from the persistent store.

Core Data and SwiftUI handled a lot of the work for you automatically, and that’s by design!

In addition to Core Data handling the persistence for you, the property observer FetchRequest handles the fetching of data and manages updating the views if the persistent store changes.

You can see this in action by adding a new RocketLaunch.

Name: A night time launch!
Launchpad: Out on the coastline
Date: 5/1/22

When you save, the view should automatically update as the state changes. With SwiftUI and Core Data saving and retrieving data is very easy.

In the next video let’s talk about how you can sort this data.