SectionedFetchRequest, sweet, sweet automagic goodness!
Every good language API includes functions made to help you in some way, write less code, manage tedious tasks, process thousands of records in milliseconds and other, generally useful features. From time to time though, you come across a function that substantially makes the world a better place. SectionedFetchRequest, new this year for SwiftUI 3, is just such a function.
Background
I recently worked on an app listing daily activities I was tracking. I wanted to group those activities by day, to make the UI look a little nicer and make it easier to find activities from a certain day. For this app, each row in the UI was made up of one or more records from the database, so I couldn’t easily group them with a standard List component. In order to build a grouped-by-day view, I had to write an algorithm that built a multidimensional array for the SwiftUI List component to consume and display my grouped list. The code for the algorithm was over 100 lines long and included SwiftUI components since as part of the list, I was also including the view that would be navigated to when tapping on the row. I later refactored some of the view code into a separate view, but still had to manage a representation of the view in the algorithm. This refactor saved a few lines of code, but didn’t change the overall structure, the same decisions still had to be made to create the same multidimensional array.
After much searching and reading Stack Overflow answers…
Using the algorithm and multidimensional array worked, but I didn’t have a tight connection to the database. This app is also connected to iCloud, more automagic to be covered in a future post, so incoming changes couldn’t be displayed until the user refreshed the view manually. This clumsy connection to the database started to manifest in other bugs and I knew this wasn’t a good solution. After much searching and answer reading on Stack Overflow, I stumbled on SectionedFetchRequest. The clouds parted and sunbeams shown to illuminate this gem of a function, ahem, once I read all the documentation and saw how it was used in a sample project!
Voilà!
With a new column in my Records table and three new lines of code, and over 100 fewer lines of old code, I was able to implement a grouped view that was very tightly connected to the database. iCloud updates would propagate to the Core Data database and the view would immediately update, without any user interaction, showing the new data!
This line is part of creating a record object that populates the CreatedDay field for an activity record:
recordObject.createdDay = currentDateTime!.formatted(date: .abbreviated, time: .omitted)
These two lines of code set up the “Sectioned” Fetch Request and the “Sectioned” Fetch Result consumed by the List component:
@SectionedFetchRequest(sectionIdentifier: \\\\.createdDay, sortDescriptors: [SortDescriptor(\\\\.createdDay, order: .reverse), SortDescriptor(\\\\.fieldOrder, order: .forward)], animation: .default) private var records: SectionedFetchResults<String?, Records>
In the above code, I specified the section identifier as createdDay, and sorted by createdDay in reverse order to show the most recent records first. I also included a second sort field, fieldOrder, to control how records are shown in the detail view, more of a good example of using multiple sortDescriptors. The second line is the result, SectionedFetchResults with the results still in a multidimensional array, but not one I had to build.
Using the SectionedFetchResults (records) (not new code):
List(records) { section in Section(header: Text(section.id!)) { ForEach(section) { record in
Show me more!
Apple has provided a sample app, downloadable from here: https://developer.apple.com/documentation/coredata/loading%5Fand%5Fdisplaying%5Fa%5Flarge%5Fdata%5Ffeed, that includes a good example of SectionedFetchRequest and SectionedFetchResults, in addition to some other good gems. Open this project in Xcode and search for SectionedFetchRequest to see how it’s being used. For Apple’s official developer documentation on SectionedFetchRequest, check here and for SectionedFetchResults go here.
This is just one of many nuggets in SwiftUI. I’ll be back here soon to share more as well as other Swift and SwiftUI goodness like iCloud integration. What golden nuggets of goodness have you found in SwiftUI or Swift. Let’s continue the conversation in the comments below.