Parcker
Parcker

Reputation: 219

Populate objects in TableView sections by months order

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

Answers (1)

vadian
vadian

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

Related Questions