Adrian
Adrian

Reputation: 16735

Grouping results with SwiftData

I have an array of objects that I'm able to render in a SwiftUI view. It's very simple to display them as a List, however I'd like to create sections and group by one of the elements' properties.

I tried up using Dictionary(grouping:by:) and then sorting by the dictionary's keys to get the sections, however this slows the UI down. It feels like I'm doing something wrong.

            List {
                ForEach(myArray.keys.sorted(), id: \.self) { mySection in
                    Section(header: Text(mySection)) {
                        ForEach(myArray[mySection] ?? []) { element in
                            NavigationLink {
                                DetailView(element: element)
                            } label: {
                                ElementRow(element: element)
                            }
                        }

                    }
                }
            }

Is there a more efficient way than Dictionary(grouping:by:) to group data retrieved from SwiftData into sections?

Upvotes: 3

Views: 2579

Answers (2)

Adrian
Adrian

Reputation: 16735

I found a framework on GitHub called SectionedQuery which does exactly what I need it to:

    @State private var searchTerm = ""

    @SectionedQuery(sectionIdentifier: \MyObject.id ,
                        sortDescriptors: [
        SortDescriptor(\MyObject.property1),
        SortDescriptor(\ MyObject.property2)
    ],
           animation: .smooth
    )
    var sections

    // stuff

    List {
        // my list consuming sections
    }
    .searchable(text: $searchTerm)

To use it with a predicate, I did the following:

List {
    // list code
}
.searchable(text: $searchTerm)
.onChange(of: searchTerm) {
    togglePredicate()
}

func togglePredicate() {
    guard !searchTerm.isEmpty else {
        sections.predicate = nil
        return
    }

    sections.predicate = #Predicate<MyThing> {
        $0.someProperty.localizedStandardContains(searchTerm)
    }
}

Upvotes: 1

malhal
malhal

Reputation: 30746

Instead of List try OutlineGroup for your grouped data.

You might need to transform your data into groups which you can do in a computed property in the parent View's body where you init the View that contains the OutlineGroup.

Upvotes: 0

Related Questions