I have a Data class as follows:
class Data: Hashable, Equatable {
var id: Int = 0
var name: String = ""
var date: Date = Date()
var paymentStatus: Bool = false
static func == (lhs: Data, rhs: Data) -> Bool {
return lhs.id ==
}
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
}
var data1: Data {
let data = Data()
data.id = 1
data.name = "John"
data.date = Calendar.current.date(byAdding: DateComponents(day: -6), to: Date())!
data.paymentStatus = true
return data
}
var data2: Data {
let data = Data()
data.id = 2
data.name = "Peter"
data.date = Date()
data.paymentStatus = false
return data
}
I’m trying to display the data in sections as follows:
struct ContentView: View {
var data: [Data] = [data1, data2]
var body: some View {
List {
ForEach(groupByDate(data), id: \.self) { studentsInMonth in
Section(header:Text(Date(), style: .date)) {
ForEach(data, id:\.self) { item in
HStack {
Text(item.name)
padding()
Text(item.date, style: .time)
if(item.paymentStatus == false) {
Image(systemName: "person.fill.questionmark")
.foregroundColor(Color.red)
} else {
Image(systemName: "banknote")
.foregroundColor(Color.green)
}
}
} // ForEach ends here...
} // section ends here
} // ForEach ends here
} // List ends here
}
}
func groupByDate(_ data: [Data]) -> [Date: [Data]] {
let empty: [Date: [Data]] = [:]
return data.reduce(into: empty) { acc, cur in
let components = Calendar.current.dateComponents([.year, .month], from: cur.date)
let date = Calendar.current.date(from: components)!
let existing = acc[date] ?? []
acc[date] = existing + [cur]
}
}
Not sure what mistake I’m making, but its throwing two errors:
Appreciate any help
Right now, you're trying to iterate through a Dictionary
using ForEach
, which doesn't work -- ForEach
expects a RandomAccessCollection
, which is most often, an Array
.
Instead, you can iterate over just the keys of the Dictionary
.
struct ContentView: View {
var data: [Data] = [data1, data2]
var body: some View {
let grouped = groupByDate(data)
List {
ForEach(Array(grouped.keys), id: \.self) { key in
let studentsInMonth = grouped[key]!
Section(header:Text(key, style: .date)) {
ForEach(studentsInMonth, id:\.self) { item in
HStack {
Text(item.name)
padding()
Text(item.date, style: .time)
if(item.paymentStatus == false) {
Image(systemName: "person.fill.questionmark")
.foregroundColor(Color.red)
} else {
Image(systemName: "banknote")
.foregroundColor(Color.green)
}
}
} // ForEach ends here...
} // section ends here
} // ForEach ends here
} // List ends here
}
}
Although the above works, I'd consider refactoring your groupByDate
function so that it returns an Array
directly instead of having to go through the above transformations.
Also, unrelated to your question, but right now, in your header, you're displaying a date -- you get just the year
and month
, but then display it as a full date, so the header says "January 1, 2022" for all the January dates. You probably want to refactor this to just show the month and year.