Как сгруппировать сообщения в UITableView (пузыри чата) по датам (разделам)? - PullRequest
1 голос
/ 20 января 2020

У меня есть приложение чата. Все работает хорошо, за исключением случаев, когда я пытаюсь сгруппировать сообщения чата в разделы, основанные на датах сообщений. При первой загрузке chatController все загружается нормально и точно группируется, но в ту минуту, когда новое сообщение отправляется или принимается, и tableView перезагружается, все дублируется (разделы со строками дублируются снова и снова)

Итак, у меня есть структура или модель данных, подобная этой:

struct Chats {
    let text, fromId, toId: String
    let isIncoming: Bool
    let date: Date

    init(dictionary: [String:Any]) {
        self.text = dictionary["text"] as? String ?? ""
        self.fromId = dictionary["fromId"] as? String ?? ""
        self.toId = dictionary["toId"] as? String ?? ""
        self.date = dictionary["date"] as? Date ?? Date()
        self.isIncoming = Auth.auth().currentUser?.uid != self.fromId
    }
}

Вот что я пробовал:

var messagesFromServer = [Chats]()
var chatMessages = [[Chats]]()

override func viewDidLoad() {
        super.viewDidLoad()
        setupViews()
        fetchMessages()
    }

   fileprivate func fetchMessages(){
        guard let currentUid = Auth.auth().currentUser?.uid else {return}
        let query = Firestore.firestore().collection("connections").document(currentUid).collection(connection.uid).order(by: "date")

        query.addSnapshotListener { (snapshot, error) in
            if let error = error{
                ProgressHUD.showError("Something went wrong. \(error.localizedDescription)")
                return
            }
            snapshot?.documentChanges.forEach({ (change) in
                if change.type == .added{
                    let dictionary = change.document.data()
                    self.messagesFromServer.append(.init(dictionary: dictionary))
                }
            })
            self.attemptToAssembleGroupedMessages { (assembled) in
                if assembled{
                    self.tableView.reloadData()
                }
            }
        }
    }

    fileprivate func attemptToAssembleGroupedMessages(completion: (Bool) -> ()){
        let groupedMessages = Dictionary(grouping: messagesFromServer) { (element) -> Date in
            return element.date.reduceToMonthDayYear()
        }

        // provide a sorting for the keys
        let sortedKeys = groupedMessages.keys.sorted()
        sortedKeys.forEach { (key) in
            let values = groupedMessages[key]
            chatMessages.append(values ?? [])
            let assembled: Bool = true
            completion(assembled)
        }
    }

Объяснение того, что я сделал: В основном Я попал в базу данных и храню все сообщения и данные в переменной messagesFromServer. Это отлично работает. Проблема возникает, когда я пытаюсь сгруппировать содержимое этой переменной на основе даты в новую переменную, которая называется chatMessages (это делается с помощью функции tryToAssembleGroupMessages )

Если вы, ребята, заинтересованы в поиске при том, как табличное представление извлекает данные, вот код:

extension ChatController: UITableViewDelegate, UITableViewDataSource{

    //How many sections
    func numberOfSections(in tableView: UITableView) -> Int {
        return chatMessages.count
    }

    //What is the view in each of these sections
    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        if let firstMessageInSection = chatMessages[section].first {
            let dateFormatter = DateFormatter()
            dateFormatter.dateFormat = "MM/dd/yyyy"
            let dateString = dateFormatter.string(from: firstMessageInSection.date)

            let label = ViewForDateHeaderLabel()
            label.text = dateString

            let containerView = UIView()
            containerView.addSubview(label)
            label.centerXAnchor.constraint(equalTo: containerView.centerXAnchor).isActive = true
            label.centerYAnchor.constraint(equalTo: containerView.centerYAnchor).isActive = true

            return containerView
        }
        return nil
    }

    //What is the height of the view in each of these Sections?
    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        return 50
    }

    //How many rows in each section?
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return chatMessages[section].count
    }

    //What is in each of these rows?
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cellId", for: indexPath) as! ChatCell
        let chatMessage = chatMessages[indexPath.section][indexPath.row]
        cell.chatMessage = chatMessage
        return cell
    }
}

Ответы [ 2 ]

0 голосов
/ 20 января 2020

Похоже, вы добавляете все сообщения в chatMessages.append, а не только новые или измененные. Решением грубой силы может быть добавление chatMessages = [] перед sortedKeys l oop.

. Вы также можете добавить своего рода отметку времени к своим сообщениям, а затем добавлять только новые сообщения. Не уверен, какой из них будет более эффективным или подходящим для вашего конкретного случая c - вам придется проверить это самостоятельно.

0 голосов
/ 20 января 2020

Я понял, что добавляю все сообщения снова и снова, чтобы попытаться сгруппировать их. Хорошее решение, которое сработало, - очистить массив перед выполнением операции группировки.

fileprivate func attemptToAssembleGroupedMessages(completion: (Bool) -> ()){
        chatMessages.removeAll() //SOLUTION
        let groupedMessages = Dictionary(grouping: messagesFromServer) { (element) -> Date in
            return element.date.reduceToMonthDayYear()
        }

        // provide a sorting for the keys
        let sortedKeys = groupedMessages.keys.sorted()
        sortedKeys.forEach { (key) in
            let values = groupedMessages[key]
            chatMessages.append(values ?? [])
            let assembled: Bool = true
            completion(assembled)
        }
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...