Reputation: 219
I have an array of objects that contain Date property. I want to distribute them in UITableView sections according to their month by month order. How I can do that?
My model:
class Birthday: Object {
@objc dynamic var name: String = ""
@objc dynamic var date: Date = Date()
@objc dynamic var dayLeft: Int = 0
@objc dynamic var userImageData: Data?
}
First I use the next code with DateFormatter:
var grouped: [String: [Birthday]] = [:]
grouped = Dictionary(grouping: birthdaysList) { item -> String in
let calendar = Calendar.current
let components = calendar.dateComponents([.year, .month], from: item.date)
let date = calendar.date(from: components) ?? Date(timeIntervalSince1970: 0)
return date.monthAsString()
}
extension Date {
func monthAsString() -> String {
let df = DateFormatter()
df.setLocalizedDateFormatFromTemplate("MMM")
return df.string(from: self)
}
}
Then I use:
struct Section {
let month: String
let birthdays: [Birthday]
}
var sections: [Section] = []
let keys = Array(grouped.keys)
sections = keys.map({Section(month: $0, birthdays: grouped[$0]!)})
But I need to sort month names in order. January, february etc. How this can be done?
I try to return tuple from my code, but get error
Declared closure result '(String, Int)' is incompatible with contextual type 'String'
grouped = Dictionary(grouping: birthdaysList) { item -> (String, Int) in
let calendar = Calendar.current
let components = calendar.dateComponents([.year, .month], from: item.date)
let date = calendar.date(from: components) ?? Date(timeIntervalSince1970: 0)
return (date.monthAsString(), components.month!)
}
Upvotes: 0
Views: 152
Reputation: 285079
Create a wrapper struct
struct Section {
let month : String
let birthdays : [Birthday]
}
then map the grouped dictionary to an array of Section
let keys = Array(grouped.keys)
let sections = keys.map({Section(month: $0, birthdays: grouped[$0]!)})
sections
represent the sections, birthdays
the rows, month
the section header titles.
Edit:
To be able to sort the months by their ordinal number return the number in front of the month name
grouped = Dictionary(grouping: birthdaysList) { item -> String in
let calendar = Calendar.current
let components = calendar.dateComponents([.year, .month], from: item.date)
let date = calendar.date(from: components) ?? Date(timeIntervalSince1970: 0)
return "\(components.month!)_" + date.monthAsString()
}
And modify the mapping code
let keys = grouped.keys.sorted{$0.localizedStandardCompare($1) == .orderedAscending}
let sections = keys.map({Section(month: $0.components(separatedBy:"_").last!, birthdays: grouped[$0]!)})
Upvotes: 1