Integrate Combine Into an App

Aug 5 2021 · Swift 5.4, macOS 11.3, Xcode 12.5

Part 2: Integrate with Core Data & Unit Test

08. Use @FetchRequest to Get Core Data Entries

Episode complete

Play next episode

Next
About this episode
Leave a rating/review
See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 07. Create the Core Data Stack Next episode: 09. Test with Given-When-Then

Get immediate access to this and 4,000+ other videos and books.

Take your career further with a Kodeco Personal Plan. With unlimited access to over 40+ books and 4,000+ professional videos in a single subscription, it's simply the best investment you can make in your development career.

Learn more Already a subscriber? Sign in.

Heads up... You've reached locked video content where the transcript will be shown as obfuscated text.

At this point, we've written helper methods to save to and delete from the Core Data database. But once we have data there, we need a way to fetch it from the database and keep the UI up to date. Luckily in iOS 13, a property wrapper was introduced that can help with that: @FetchRequest. It uses a generic result where the result inherits from NSFetchRequestResult. Let's look at the different initializers that it has. This initializer looks very similar if you've used Core Data in the past since it mirrors NSFetchRequest. The argument list consists of an NSEntityDescription, which is the entity you're trying to fetch from the database. An array of NSSortDescriptors, which describe how to sort the return data. And two optional arguments, an NSPredicate, which can help filter the set of fetch results, and an animation, which governs the animation used for any changes to the fetch results, which can come into play when keeping a SwiftUI list up to date, for example. This initializer is available when the result inherits from NSManagedObject, and is similar to the last one, except there is no NSEntityDescription. This is inferred using result.entity. The last two initializers take in a normal NSFetchRequest, as well as either an animation or a transaction, both of which are used when the fetch results change. With that knowledge in place, let's look at how to save, fetch, and delete jokes from the database in a demo. Having placed the ManagedObjectContext in the SwiftUI environment in the last episode, it's easy to grab that and use it in any view. So add it to the view's jokeView.swift file before the view model is declared. Now, go down to the handle method. And under the default case, add a check for decisionState equals .liked. This will capture the case when the user likes the joke, and therefore, wants it's saved for helping them become the life of the party in the future. Thanks to the helper method defined earlier, it's easy to save the joke now, since we have the view context in hand. Before we leave this file, we need to pass the view context into the savedJokesView so that it has access. This can be done by passing the view context into the environment when the savedJokesView was made up above in the sheet modifier. Now, with savedJokes in the database, you can populate a SwiftUI view with those jokes. Go to views, savedJokesView.swift, and again, you'll need a reference to the view context that you have stored in the SwiftUI environment. The current code declares an array of strings to represent the jokes. Replace that with a @FetchRequest. If you are familiar with NSFetchRequests at all, this property wrapper works in a similar fashion. It will, using this version of the initializer, grab all jokeManagedObjects from the database, sort them using the value property of the jokeManagedObject, and animate them into the list that shows them with the default animation. This property wrapper also sets up a publisher-subscriber relationship. As changes to the database take place, the fetch is automatically repeated, and the UI is updated since the underlying state has changed. This is very similar to the normal @State binding behavior in SwiftUI with the addition of the fetchRequest to handle the updating of the data. To handle deletion of jokes, go to the forEach block of code and update the .onDelete modifier to use the delete method we defined in the earlier episode. Recall that this takes in an IndexSet, so it works perfectly with lists that come out of forEach. Now, let's run this in the simulator. We can add jokes to the database by swiping right, look at our list of saved jokes which uses the @FetchRequest and delete jokes from the list, as well. That adds the last bit of features for our app, but we really need some unit tests, which we'll handle next.