How it works
Use a SectionedFetchRequest property wrapper to retrieve Core Data managed objects from a view and have SwiftUI deliver them already grouped into sections. Unlike a flat FetchRequest, which hands you a single ordered collection, SectionedFetchRequest splits its results by a key path you choose and exposes the groups as a SectionedFetchResults value, so each section arrives with its own identifier and contents. Reach for it when your data is naturally partitioned — items by category, events by date, contacts by initial — and you want the store, rather than your view code, to do the grouping. Because the request lives in the view, the sections stay in sync with the managed object context and refresh automatically as the underlying data changes.
Declare the request with @SectionedFetchRequest
Apply the property wrapper to a property in your view and supply a sectionIdentifier key path together with sort descriptors. The sectionIdentifier names the field that defines each group's boundary, and the sort descriptors must order results so that rows sharing a section value are adjacent. In the example the page's
categoryfield plays the grouping role that this key path would target —"Fruit"and"Vegetable"become the section boundaries.Read the grouped results as SectionedFetchResults
The wrapped value is a SectionedFetchResults collection whose elements are sections rather than individual objects. You iterate it to walk the groups, and each element carries an
idmatching its sectionIdentifier plus the managed objects that fall under it. This two-level shape mirrors thesectionsarray in the example, where each entry pairs a title with itsitems.Render each section's id and elements
Drive a List by iterating the results: the outer loop yields one section per sectionIdentifier value, and the inner loop yields that section's objects. Use the section's identifier for the header and its contents for the rows — the structure the code shows with
ForEach(sections, id: \.0)wrapping aSection(header: Text(title))and an innerForEach(items)over eachitem.Customize the underlying query and grouping at runtime
SectionedFetchResults exposes a settable
sectionIdentifier,nsSortDescriptors, andnsPredicate, letting you re-section, re-sort, or filter without redeclaring the request. Assigning a new sectionIdentifier reshapes the same data into different groups — the equivalent of swapping which field ofItem(itscategoryversus itsname) decides theSectionboundaries.
category field to name (for example, the first letter of item.name) so the request re-sections the same items alphabetically, and watch the Section(header:) titles change from "Fruit"/"Vegetable" to letter buckets.Example & preview
Press Run live & edit to compile it in your browser — then edit the Swift on the left and the preview re-renders live.
struct SectionedFetchRequestDemo: View {
struct Item: Identifiable {
let id = UUID()
let name: String
let category: String
}
let sections: [(String, [Item])] = [
("Fruit", [Item(name: "Apple", category: "Fruit"), Item(name: "Banana", category: "Fruit")]),
("Vegetable", [Item(name: "Carrot", category: "Vegetable")])
]
var body: some View {
List {
ForEach(sections, id: \.0) { title, items in
Section(header: Text(title)) {
ForEach(items) { item in
Text(item.name)
}
}
}
}
.padding()
}
}