Dynamic Core Data with SwiftUI Tutorial for iOS
Learn how to take advantage of all the new Core Data features introduced in iOS 15 to make your SwiftUI apps even more powerful. By Mark Struzinski.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Dynamic Core Data with SwiftUI Tutorial for iOS
20 mins
Updating Sorts
Trying to sort right now won’t work at all. Try changing the sort options — eventually, the app will crash and display this message:
Thread 1: "UITableView internal inconsistency: encountered out of bounds global row index while preparing batch updates"
This error is caused by a mismatch in section and row data when you sort on one property but group on another. The fetch results must be sorted in section order for the list to work. To fix this, you need to add an additional property to your sort option struct
. Open FriendSort.swift and add a new property to FriendSort
:
let section: KeyPath<Friend, String>
Next, update sorts
to add the new section
parameter to all of the initializers:
static let sorts: [FriendSort] = [
FriendSort(
id: 0,
name: "Meeting Place | Ascending",
descriptors: [
SortDescriptor(\Friend.meetingPlace, order: .forward),
SortDescriptor(\Friend.name, order: .forward)
],
section: \Friend.meetingPlace),
FriendSort(
id: 1,
name: "Meeting Place | Descending",
descriptors: [
SortDescriptor(\Friend.meetingPlace, order: .reverse),
SortDescriptor(\Friend.name, order: .forward)
],
section: \Friend.meetingPlace),
FriendSort(
id: 2,
name: "Meeting Date | Ascending",
descriptors: [
SortDescriptor(\Friend.meetingDate, order: .forward),
SortDescriptor(\Friend.name, order: .forward)
],
section: \Friend.meetingDay),
FriendSort(
id: 3,
name: "Meeting Date | Descending",
descriptors: [
SortDescriptor(\Friend.meetingDate, order: .reverse),
SortDescriptor(\Friend.name, order: .forward)
],
section: \Friend.meetingDayDescending)
]
Each sort option now has a section key path. Note that the two meeting date options have different key paths — without this, you get a crash when switching between the two date options.
Go back to ContentView.swift. Here, you can replace the initial section with the new property from the default sort option. In the @SectionedFetchRequest
property, replace the section identifier with the following code:
sectionIdentifier: FriendSort.default.section,
Still in ContentView.swift, update the application of sorts to the list by replacing the body of the .onChange
closure with this::
let request = friends
request.sectionIdentifier = selectedSort.section
request.sortDescriptors = selectedSort.descriptors
This code might seem a little strange — why is let request = friends
there? Why not just update friends
directly? The reason is that you are now making two changes to the fetch request, but they both need to be evaluated at the same time. Each time you reference friends
, it’ll commit any changes to the fetch request. So if you change friends.sectionIdentifier
, then change friends.sortDescriptors
, the fetch request with the updated section identifier will be evaluated, before you have had chance to update the sort descriptors. As you’ve seen earlier, this can cause crashes, as the results have to be in section order. Pulling out the request into a local reference and updating that means that the changes won’t be evaluated until friends
is accessed again when the view body is recomputed.
Build and run to test your new changes. You’ll see sorting by meeting place will group by section and perform a sort on meeting place name.
Performing a sort by meeting date will change the grouping to meeting date, then perform a sort on that property.
Where to Go From Here?
Download the completed project files by clicking the Download Materials button at the top or bottom of the tutorial.
If you want to dig deeper into working with Core Data and SwiftUI together, check out this Core Data with SwiftUI tutorial and this Core Data with CloudKit tutorial.
We hope you enjoyed this tutorial. If you have any questions or comments, please join the forum discussion below!