2

I have a Firebase snapshot listener that checks for new documents, adds them to an array (the collectionView datasource), and then reloads the collectionView. However, I'm getting duplicate cells in the collectionView. I currently have 3 objects in my Firestore collection but they get duplicated for a total of 9 cells.

I even added a check for the index so reloadData only happens after it reaches the end of the array. Here's the relevant code:

messageListener = query.addSnapshotListener { querySnapshot, error in
    guard let snapshot = querySnapshot else {
        print("Error listening for channel updates: \(error?.localizedDescription ?? "No error")")
        return
    }
    
    snapshot.documentChanges.forEach { change in

        if change.type == .added {
            for document in snapshot.documents{
                
                 ....

                let newMessage = Message(sender: newSender, messageId: document.documentID, sentDate: date, text: text)
                
                self.messages.append(newMessage)
                
                guard let index = snapshot.documents.index(of: document) else {return}
                
                if index == (snapshot.documents.count - 1) {
                    self.messagesCollectionView.reloadData()
                }
            }
        }
    }
}

It correctly counts down the index so it eventually reaches 2 == 2 to reloadData. However, it then starts the process over again two other times for a total of three (3 objects loaded three times for a total of 9 cells). Any idea how I can improve this logic flow to stop the duplicates?

Thanks!!

EDIT 1

extension ChatViewController: MessagesDataSource {
    
    func currentSender() -> Sender {
        //guard let currentUserID = User.current?.key else {return nil}
        let newSender = Sender(id: (User.current?.key)!, displayName: (User.current?.username)!)
        return newSender
    }
    
        func numberOfSections(in messagesCollectionView: MessagesCollectionView) -> Int {
    return 1
}

func numberOfItems(inSection section: Int, in messagesCollectionView: MessagesCollectionView) -> Int {
    return messages.count
}
    func messageForItem(at indexPath: IndexPath, in messagesCollectionView: MessagesCollectionView) -> MessageType {
        return messages[indexPath.section]
        
        func cellTopLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString? {
           
            return NSAttributedString(string: MessageKitDateFormatter.shared.string(from: message.sentDate), attributes: [NSAttributedString.Key.font: UIFont.boldSystemFont(ofSize: 10), NSAttributedString.Key.foregroundColor: UIColor.darkGray])
        }
        
        func messageTopLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString? {
            let name = message.sender.displayName
            return NSAttributedString(string: name, attributes: [NSAttributedString.Key.font: UIFont.preferredFont(forTextStyle: .caption1)])
        }
        
        func messageBottomLabelAttributedText(for message: MessageType, at indexPath: IndexPath) -> NSAttributedString? {
            
            let dateString = formatter.string(from: message.sentDate)
            return NSAttributedString(string: dateString, attributes: [NSAttributedString.Key.font: UIFont.preferredFont(forTextStyle: .caption2)])
        }
    }
}
auspicious99
  • 3,902
  • 1
  • 44
  • 58
winston
  • 3,000
  • 11
  • 44
  • 75
  • Could you show us your code numberOfSection, numberOfRow, cellForItem? – qtngo Feb 18 '19 at 03:23
  • OK, I updated the Edit and I'm still getting issues. My numberOfSections has been correctly set to 1 and my numberOfItems has been set to my array.count. Oddly enough now the first chat message in my collection just get repeated 9 times – winston Feb 18 '19 at 03:43
  • Check your self.messages, I highly doubt it has 9 values. This maybe caused by appending newMessage 3 * 3 times (3 document change event, each event add 3 message in the array). Maybe you should do self.messages.removeAll() before line "for document in snapshot.documents"? – qtngo Feb 18 '19 at 03:57
  • "each event adds 3 messages in the array" that has to be it. I didn't realize that's what was happening, but now I understand what these "change events" are. Is there a better way to set this up? Also I added the removeAll and it reduced the duplicates from 9 to 3 – winston Feb 18 '19 at 04:04
  • For improving it depends a lot on your specification, do you want to handle the case of update, delete, ...etc Anyway, you must always reset your message array before repopulate your snapshot documents, otherwise it will added up multiple times. If this resolve your problem, may I write an answer so you can vote up and approuve? – qtngo Feb 18 '19 at 04:19
  • Yup, that removeAll did end up working by the way. Thanks for for your help. I also had to remove my numberOfItems function, and revert the numberOfSections to equal my array count again – winston Feb 18 '19 at 04:20

2 Answers2

6

messages array must be reset before repopulate snapshot document. You can add self.messages.removeAll() before the line for document in snapshot.documents

qtngo
  • 1,594
  • 1
  • 11
  • 13
0

You must clear the array holding your objects after

collectionView?.refreshControl?.beginRefreshing()
self.messages = []

And then call

self.collectionView?.reloadData()

Otherwise, you'll get the "Index out of Range" Error

ISS
  • 406
  • 6
  • 24