Kenny Wyland
Kenny Wyland

Reputation: 21880

SwiftUI List with Sections fetched from Core Data

Back in objective-c, I could fetch a sectioned list of objects from Core Data using something like this:

self.fetchedResultsController = [[NSFetchedResultsController alloc]
         initWithFetchRequest:fetchRequest
         managedObjectContext:managedObjectContext
           sectionNameKeyPath:@"ispurchased"
                    cacheName:nil];

And then the NSFetchedResultsController would automatically give me the data in sections and rows.

I'm experimenting with SwiftUI for the first time and I'm trying to figure out how to achieve a sectioned List like that. I've found lots of examples that use some canned array data that is pre-structured in the sectioned fashion, but I can't figure out how to do a sectioned FetchRequest nor how to integrate that with the List.

struct EasyModeList: View {
    @FetchRequest(
        sortDescriptors: [
            NSSortDescriptor(keyPath: \EasyMode.ispurchased, ascending: true),
            NSSortDescriptor(keyPath: \EasyMode.ispurchasable, ascending: false),
            NSSortDescriptor(keyPath: \EasyMode.name, ascending: true),
        ],
        animation: .default)
    var easymodes: FetchedResults<EasyMode>

    @Environment(\.managedObjectContext)
    var viewContext

    var body: some View {
        List {
            ForEach(self.easymodes, id: \.self) { easymode in
                NavigationLink(
                    destination: DetailView(easymode: easymode)
                ) {
                    VStack {
                        Text("\(easymode.name!)")
                    }
                }
            }
        }
    }
}

Does SwiftUI easily support those kinds of sectioned lists? Is there a different paradigm that I should be shifting my brain to?

Upvotes: 8

Views: 1101

Answers (1)

Michael Ozeryansky
Michael Ozeryansky

Reputation: 8053

I am also looking for a proper solution to this. For now I'll share what I've tried. My sections are by string titles, but I'll adapt it for your data.

@FetchRequest(...) var managedEasyModes: FetchedResults<EasyMode>

private var easyModes: [String: [EasyMode]] {
    Dictionary(grouping: managedEasyModes) { easymode in
        easymode.ispurchased ? "Purchased" : "Not Purchased"
    }
}

private var sections: [String] {
    easyModes.keys.sorted(by: >)
}

var body: some View {
    ForEach(sections, id: \.self) { section in
        Section(header: Text(section)) {
            ForEach(easyModes[section]!) { easyMode in
                NavigationLink(destination: EasyModeView(easyMode: easyMode)) {
                    EasyModeRowView(easyMode: easyMode)
                }
            }
        }
    }
}

Upvotes: 4

Related Questions