Core Data: Beyond the Basics

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

Part 1: Fetching & Displaying Launches

10. Challenge - Displaying Tags

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: 09. Challenge - Adding Tags Next episode: 11. Transient Properties

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.

Transcript: 10. Challenge - Displaying Tags

Now that your object graph can store tags you need a way to display them. This is part two of your challenge - to display all the tags that have been added to launches so far.

To keep it simple, add a Tags button in the nav bar in the Launches view that displays a list of tags. There’s one catch though, you need to display the tags that have been added only to the launches associated with the specific list and not all tags

As always when you’re done, I’ll walk you through my implementation.

Let’s start by creating a view to display our tags. Add a new group under Views and name it Tags. Then add a new SwiftUI file to the group with the name TagsView.

We’ll flesh this out in just a second. Back in LaunchesView add code to display the new view you just added. Start with a state property to keep track of whether the modal view is being displayed.

@State var isShowingTagsModal: Bool = false

At the bottom of the view, add a Button as a trailing navigation bar item

.navigationBarItems(trailing:
  Button(action: { self.isShowingTagsModal.toggle() }) {
    Text("Tags")
  }.sheet(isPresented: self.$isShowingTagsModal, content: {
    TagsView()
  })
)

You’ll use the sheet(isPresented:content:) method to display the TagsView as a modal.

Build and run the app. If you navigate to a list and tap on tags the modal view should show. Awesome.

We know that you’re going to need the managed object context, so let’s add that to the modal view’s environment object. At the top of TagsView add the following:

@Environment(\.managedObjectContext) var viewContext

Now you might think that your next step is creating a fetch request with some sort of predicate to fetch the right tags but it’s actually a lot more straightforward.

Since you’ve defined relationships between all of these entities you can leverage those relationships and let Core Data do the work automatically. In TagsView, add a property to initialize the view with tags.

let tags: [Tag]

You’ll display these tags in a list view that you’ll embed in a nav stack.

NavigationView {
  VStack {
    List {
      Section {
        ForEach(tags, id: \.self) {tag in 
          Text(tag.title)
        }
      }
    }
  }
}

Let’s also add a navigation bar title on the VStack

.navigationBarTitle(Text("Tags"))

We won’t bother with a dismiss or save button; instead you’ll just use the swipe to dismiss action that comes for free with modals.

You’ll need to fix the preview to accommodate the changes you made.

struct TagsView_Previews: PreviewProvider {
    static var previews: some View {
      let context = PersistenceController.preview.container.viewContext
      let tag = Tag(context: context)
      tag.title = "Test"
      return TagsView(tags: [tag])
    }
}

Back in LaunchesView let’s add a computed property to get all the associated tags.

var tags: Array<Tag> {}

Since we want to get all tags defined on all launches associated with this list, let’s start by getting the launches.

let tagsSet = launchList.launches

Next you’ll map over the launches and get the tags for each of them. Since tags are optional you’ll need to use compactMap

let tagsSet = launchList.launches.compactMap({$0.tags})

This is going to return an array of sets of tags. You need a single set, so let’s call reduce on this and combine each partial result into a single one. Since you’re using a Set, the compiler will automatically handle duplicates for us.

let tagsSet = launchList.launches.compactMap({$0.tags}).reduce(Set<Tag>(), {(result, tags) in
  var result = result
  result.formUnion(tags)
  return result
})

Finally you can return this as an array

return Array(tagsSet)

In the tags button closure at the bottom you can use this to initialize the TagsView

TagsView(tags: self.tags)

Build and run the app. Now if you navigate to a particular list and tap on the Tags button, you can see all the associated tags.

Relationships in Core Data make life a lot easier by handling a lot of the work for us. Had you not defined these relationships you would need to define a series of predicates to first fetch all the associated launches and then all the associated tags.

In the next video let’s talk about one final attribute type that comes in handy - transient properties.