Core Data: Beyond the Basics

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

Part 1: Fetching & Displaying Launches

05. Dynamically Adjust Sort Descriptors

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: 04. Filtering Using Predicates Next episode: 06. Modeling Relationships

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: 05. Dynamically Adjust Sort Descriptors

While sort descriptors can be handy to initially sort data coming out of the persistent store, you might want to provide your user the chance to sort the data in real time as they use your app. Luckily some improvements to Core Data in recent years has made that possible. Both sort descriptors and predicates for fetch requests are accessible outside of the initial fetch request declaration and can be changed on the fly. Let’s add a sort button to the Launches view.

Open LaunchesView.swift, and add an array of sort descriptors right before the body declaration:

let sortTypes = [
    (name: "Name", descriptors: [SortDescriptor(\RocketLaunch.name, order: .forward)]),
    (name: "LaunchDate", descriptors: [SortDescriptor(\RocketLaunch.launchDate, order: .forward)])
  ]

This is new in iOS 15 - the SortDescriptor type lets us define sort descriptors outside of the normal FetchRequest declaration. Before we start modifying the view, add a state property to track the index of the current sort descriptor in the array:

@State var activeSortIndex = 0

You’ll see how this is used in just a bit.

After the navigationBarTitle modifier, add the following onChange modifier:

.onChange(of: activeSortIndex) { _ in
      launches.sortDescriptors = sortTypes[activeSortIndex].descriptors
}

This modifier will monitor the state of the state property activeSortIndex and when it changes, will update the value of the sortDescriptors for the launches fetch request. What changes activeSortIndex? Glad you asked! Add the following toolbar modifier right below the onChange modifier:

.toolbar {
  Menu(content: {
    Picker(
      selection: $activeSortIndex,
      content: {
        ForEach(0..<sortTypes.count, id: \.self) { index in
          let sortType = sortTypes[index]
          Text(sortType.name)
        }
      },
      label: {}
    )
  }, label: {
    Image(systemName: "line.3.horizontal.decrease.circle.fill")
  })
}

This inserts a Picker (wrapped in a menu) into the toolbar, and presents to the user the name of each of the sort types. Pickers update the binding pointed to by their selection, so here when the menu changes, activeSortIndex is updated based on the index of the item selected. Then the onChange modifier gets triggered, the sort descriptor is changed, and the view gets refreshed. Let’s try it out.

Build and run the app. There is now an icon in the upper right hand corner. Tap on that and you can see that the Name sort descriptor is currently selected. Choose the Launch Date instead, and when you do so, the items in the list get resorted. You can change back to Name to get the original order. Predicates can also be updated this way - you’ll see that later in the course.

In the next video, you’ll see how you can define relationships between entities, and all the power that provides. See you then!