chickenparm
chickenparm

Reputation: 1630

Firebase database observer in each tableViewCell

I am creating a chat application where the main view is a tableView with each row representing a chat. The row has a label for the person's name as well as a label with the latest chat message. If a user taps a row, it will segue into a chat view. I am using MessageKit for the chat framework. All is working well except I am having trouble displaying the most recent chat consistently.

Here is how my tableView looks. Please ignore the black circles, I was quickly clearing out personal photos I was using for testing.

enter image description here

I have a custom tableViewCell with the method below. This creates an observer for this specific chat starting with the most recent message.

  func getLatestChatMessage(with chatID: String) {
    guard let loggedInUserID = Auth.auth().currentUser?.uid else { return }
    DatabaseService.shared.chatsRef.child(chatID).queryLimited(toLast: 1).observe(.childAdded) { [weak self] (snapshot) in

      guard let messageDict = snapshot.value as? [String:Any] else { return }
      guard let chatText = messageDict["text"] as? String else { return }
      guard let senderId = messageDict["senderId"] as? String else { return }

      DispatchQueue.main.async {
        if senderId == loggedInUserID {
          self?.latestChatMessage.textColor = .black
        } else {
          self?.latestChatMessage.textColor = UIColor(red: 0/255, green: 122/255, blue: 255/255, alpha: 1)
        }
        self?.latestChatMessage.text = chatText
      }
    }
  }

I call this function in the TableView's method cellForRowAt after observing the chatID for this user.

  override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    ...

     DatabaseService.shared.matchedChatIdRef.child(loggedInUserID).child(match.matchedUserId).observeSingleEvent(of: .value) { (snapshot) in
            if let chatID = snapshot.value as? String {
              cell.getLatestChatMessage(with: chatID)
            }
          }
      }

Ideally this should create an observer for each chat and update the label every time there is a new message sent. The issue I am having is it sometimes works but other times seems to stop observing.

For example, if I am on the chat tableView and get a new message for one of the cells, it updates. However, if I then tap that chat to segue into a specific chat and send a message then tap the back button to go back to my tableView, the label stops updating. It appears as though my observer gets removed. Does anyone have any ideas why my observers in each cell stop working? Also, I am interested if anyone has a recommendation for a better solution to this? I am worried that creating an observer for each cell may be a poor solution.

EDIT: I've found that the observer stops working after selecting the back button or swiping back to the tableView from the chat in the screenshot below. Chat

Upvotes: 3

Views: 247

Answers (1)

chickenparm
chickenparm

Reputation: 1630

Woke up this morning and realized my issue...In the ChatViewController I was calling removeAllObservers()

I updated my code to below to just remove the observer in the chat and it fixed my issue:

  override func viewDidDisappear(_ animated: Bool) {
    super.viewDidDisappear(true)

    if let observerHandle = observerHandle, let chatID = chatId {
      DatabaseService.shared.chatsRef.child(chatID).removeObserver(withHandle: observerHandle)
    }
  }

Upvotes: 1

Related Questions