Search code examples
swiftgoogle-cloud-firestoreduplicatestableviewlistener

Duplicated rows in array populated by Firebase


I have a chatApp but for some reason, whenever a user send a message inside a room, the conversation row (displaying the last msg sent and the username who sent it) duplicate with 2 row showing the same last message and 1 row showing an older message (the one before the last one). To solve this i added a refresh function which is clearing the array and reloading the tableView but it's not practical. I don't know how to prevent this. Here's my code:

RoomViewController

var lastDocumentSnapshot: DocumentSnapshot!
var currentPage = 1
private var rooms = [Room]()

@objc func refresh() {
        self.rooms.removeAll()           
        self.tableView.reloadData()
    }
 @objc func fetchRooms() {
        var query: Query!

       tableView.refreshControl?.beginRefreshing()
       
        if rooms.isEmpty {
            query = COLLECTION_ROOMS.order(by: "timestamp", descending: false).limit(toLast: 10)
             print("First 10 room loaded")
         } else {
             query = COLLECTION_ROOMS.order(by: "timestamp", descending: false).end(beforeDocument: lastDocumentSnapshot).limit(toLast: 10)
            print("Next 10 room loaded")
            self.currentPage = self.currentPage + 1
         }
       query.addSnapshotListener { (snapshot, err) in
           if let err = err {
               print("\(err.localizedDescription)")
           } else if snapshot!.isEmpty {
               self.tableView.refreshControl?.endRefreshing()
               return
           }
           guard let lastSnap = snapshot?.documents.first else {return}
           self.lastDocumentSnapshot = lastSnap
           
           snapshot?.documentChanges.forEach({ (change) in
               let dictionary = change.document.data()
               let message = RoomMessage(dictionary: dictionary)
               let ownerID = dictionary["ownerID"] as? String ?? ""
               
               UserService.fetchUser(withUid: ownerID) { user in
                   let conversation = Room(user: user, recentMessage: message)
                   self.rooms.append(conversation)
                   self.rooms.sort(by: { $0.recentMessage.timeStamp.compare($1.recentMessage.timeStamp) == .orderedDescending })
                   self.tableView.reloadData()
               }
            })
               self.tableView.refreshControl?.endRefreshing()
               self.lastDocumentSnapshot = snapshot?.documents.first
       }
    }

Solution

  • I managed to solve the issue by adding a listener and stop listening whenever a msg is sent inside a chat.

    var listener: [ListenerRegistration] = []
    var isListening = false
    
    @objc func fetchRooms() {
           print("Fetching Room")
    
            var query: Query!
            self.isListening = true
    
           tableView.refreshControl?.beginRefreshing()
           
            if rooms.isEmpty {
               query = COLLECTION_ROOMS.order(by: "timestamp", descending: false).limit(toLast: 10)
                 print("First 10 room loaded")
             } else {
                query = COLLECTION_ROOMS.order(by: "timestamp", descending: false).end(beforeDocument: lastDocumentSnapshot).limit(toLast: 5)
                print("Next 10 room loaded")
             }
           let listener = query.addSnapshotListener { (snapshot, err) in
               if err != nil {
    //                       print("\(error.localizedDescription)")
                       } else if snapshot!.isEmpty {
                           self.tableView.refreshControl?.endRefreshing()
                           return
                       }
               guard let lastSnap = snapshot?.documents.first else {return}
               self.lastDocumentSnapshot = lastSnap
               
               snapshot?.documentChanges.forEach({ (change) in
                   if change.type == .added {
                       let dictionary = change.document.data()
                       self.rooms.append(Room(dictionary: dictionary))
                       self.rooms.sort(by: { $0.timeStamp.compare($1.timeStamp) == .orderedDescending })
                       self.tableView.reloadData()
                   }
                   if change.type == .modified {
                       self.isListening = false
                   }
                   if change.type == .removed {
                   }
               })
                   self.tableView.refreshControl?.endRefreshing()
                   self.lastDocumentSnapshot = snapshot?.documents.first
           }
           if isListening == false { listener.remove()}
        }