Bernhard Engl
Bernhard Engl

Reputation: 271

Group Array to introduce sections to UITableView in Swift

I have the following class:

ChatMessage: Codable {
    var id: Int?
    var sender: User?
    var message: String?
    var seen: Int?
    var tsp: Date?
}

The tsp is formatted like this: YYYY-MM-DD hh:mm:ss

I would like to "group" messages sent on the same day to end up with something like in this example:

let groupedMessages = [ [ChatMessage, ChatMessage], [ChatMessage, ChatMessage, ChatMessage] ]

I ultimately want to use groupedMessages in a UITableViewController to introduce sections like so:

func numberOfSections(in tableView: UITableView) -> Int {
        return groupedMessages.count 
        // would be 2 int the above
    }



    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return chatMessages[section].count 
        // would be 2 for the first and 3 for the second section
    }

What would be the most performant way of getting the sorting done? - i.e. something that also works well once the number of chatMessages to be sorted increases

Upvotes: 0

Views: 1047

Answers (4)

TheCodeTalker
TheCodeTalker

Reputation: 705

let testArray = ["2016-06-23 09:07:21", "2016-06-23 08:07:21", "2016-06-22 09:07:21", "2016-06-22 08:07:21"]

        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "YYYY-MM-DD hh:mm:ss"

        let groupDic = Dictionary(grouping: testArray) { (pendingCamera) -> DateComponents in

            let date = Calendar.current.dateComponents([.day, .year, .month], from: dateFormatter.date(from: pendingCamera)!)

            return date
        }
        print(groupDic)

You can take groupDic and return in numberOfSections and titleForHeaderInSection.

Upvotes: 0

DrewG23
DrewG23

Reputation: 437

You could try:

let cal = Calendar.current
let groupedMessages = Dictionary(grouping: self.chatMessages, by: { cal.startOfDay($0.tsp) })
let keys = groupedMessages.keys.sorted(by: { $0 > $1 })

This however would give you a dictionary like:

[
  SomeDateHere: [
    ChatMessage(id: 0, sender: User?, message: "String", seen: 1),
    ChatMessage(id: 0, sender: User?, message: "String", seen: 1)
  ],
  AnotherDateHere: [
    ChatMessage(id: 0, sender: User?, message: "String", seen: 1)
]

You could then use keys to return the section count:

return keys.count

And to get the array of messages for each dictionary item like so:

let key = keys[indexPath.section]
let messages = groupedMessages[key].sorted(by: { $0.tsp > $1.tsp })

Or to get just the count:

let key = keys[indexPath.section]
return groupedMessages[key].count

Upvotes: 2

Sulthan
Sulthan

Reputation: 130200

I would probably start by introducing a new type:

public struct CalendarDay: Hashable {
   public let date: Date

   public init(date: Date = Date()) {
       self.date = Calendar.current.startOfDay(for: date)
   }
}

extension CalendarDay: Comparable {
   public static func < (lhs: CalendarDay, rhs: CalendarDay) -> Bool {
      return lhs.date < rhs.date
   }
}

Then I would extend your message:

extension ChatMessage {
    var day: CalendarDay {
       return CalendarDay(date: tsp)
    }
}

(I am assumming tsp is not an optional, there is no reason for it to be optional).

Now, let's define a section:

struct Section {
   var messages: [ChatMessage] = []
   let day: CalendarDay

   init(day: CalendarDay) {
      self.day = day
   }
}

Let's group easily:

let messages: [ChatMessage] = ...
var sections: [CalendarDay: Section] = [:]

for message in messages {
   let day = message.day
   var section = sections[day] ?? Section(day: day)
   section.messages.append(day)
   sections[day] = section
}

let sectionList = Array(sections.values).sorted { $0.day < $1.day }

If your messages are not originally sorted, you might need to also sort messages in every section separately.

Upvotes: 0

Vladyslav Shmatok
Vladyslav Shmatok

Reputation: 434

Grouping array by date you could find here How to group array of objects by date in swift?

How to connect this to UITableView you will find here https://www.ralfebert.de/ios-examples/uikit/uitableviewcontroller/grouping-sections/

Upvotes: 0

Related Questions