I have been attempting to wrap my head round a sorting and grouping course of for a SwiftUI app I have been attempting to construct.
All of the tutorials I’ve seen have been pretty “primary” in the case of the sorting and filtering facet – significantly when utilizing SwiftData.
What I wished to include was not solely sorting by one of many attributes and ahead/reverse, but additionally grouping the information too.
For instance, that is code from the Earthquake venture by Apple (some objects eliminated for brevity):
struct QuakeList: View {
@Setting(ViewModel.self) personal var viewModel
@Setting(.modelContext) personal var modelContext
@Question personal var quakes: [Quake]
init(
sortParameter: SortParameter = .time,
sortOrder: SortOrder = .reverse
) {
swap sortParameter {
case .time:
_quakes = Question(type: .time, order: sortOrder)
case .magnitude:
_quakes = Question(type: .magnitude, order: sortOrder)
}
}
What they do in that is move within the sortParameter
and the sortOrder
to this view and it re-renders the view on change/replace.
How can I increase this so it can also deal with grouping so the quakes
variable would actually be a multidimensional array or perhaps a dictionary.
For instance, I used to be attempting to do that to carry out the rendering:
enum GroupOption { // New grouping for Part
case time
case magnitude
case none
}
struct ListScreen: View {
@Setting(ViewModel.self) personal var viewModel
@Setting(.modelContext) personal var modelContext
@Question personal var quakes: [Quake]
@State personal var groupedQuakes: [[Quake]] = [] // New multidimensional array
init(
sortParameter: SortParameter = .time,
sortOrder: ComparisonResult = .orderedAscending, // utilizing ComparisonResult to retailer the enum worth in defaults
sortGrouping: GroupOption = .none
) {
swap (sortParameter, sortOrder) {
case (.time, .orderedAscending):
_quakes = Question(type: .time, order: .ahead)
case (.time, .orderedDescending):
_quakes = Question(type: .time, order: .reverse)
case (.magnitude, .orderedAscending):
_quakes = Question(type: .magnitude, order: .ahead)
case (.magnitude, .orderedDescending):
_quakes = Question(type: .magnitude, order: .reverse)
default:
_quakes = Question(type: .time, order: .ahead)
}
swap sortGrouping {
case .time:
groupedQuakes = Dictionary(grouping: _quakes.wrappedValue, by: { $0.time })
.sorted(by: { $0.key < $1.key })
.map({ $0.worth })
case .magnitude:
groupedQuakes = Dictionary(grouping: _quakes.wrappedValue, by: { $0.magnitude })
.sorted(by: { $0.key < $1.key })
.map({ $0.worth })
case .none:
groupedQuakes = [_quakes.wrappedValue]
}
}
Besides, after I use it within the view physique it’s empty. So switching from the // 1
to // 2
makes the array of information return empty.
// 1
Record(quakes, choice: $selectedId) { quake in
QuakeRow(quake: quake)
}
// 2
Record {
ForEach(groupedQuakes, id: .self) { group in
Part {
ForEach(group) { quake in
QuakeRow(quake: quake)
}
} header: {
groupHeader(for: group)
}
}
}
// ...
func groupHeader(for group: [Quake]) -> Textual content {
guard let group = group.first else { return Textual content("Unknown") }
swap groupOption {
case .time:
return Textual content(group.time.formatted(date: .numeric, time: .omitted))
case .magnitude:
return Textual content("(group.magnitude)")
case .none:
return Textual content("All quakes")
}
}
So after I return the overall @Question personal var quakes: [Quake]
there may be an array returned with the information.
Utilizing the sorting included within the Apple check venture the quakes
are sorted accurately.
As quickly as I attempt to add in grouping and type that knowledge returns clean arrays.
Is there one thing I am overlooking?