0

I am working on a group chat app and trying to fetch the last message from a node to display the last message under the group name. Everything is working fine. When the group receives a new message, the last message is showing in the correct group and some other random groups as well. If I open the correct group and come back, all the other groups are showing the correct last message. Kindly help me with the below code.

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return groupList.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell:GroupsTableViewCell = tableView.dequeueReusableCell(withIdentifier: "GroupsTableViewCell") as! GroupsTableViewCell cell.selectionStyle = .none var user: Groupslist if groupList.count > 0 { user = groupList[indexPath.row] cell.lbl_name_group.text = user.name; cell.view_count.isHidden = true GetLastMsg(groupID: user.group_id ?? "", cell: cell) cell.img_group.image = UIImage.init(named:"final_grp") GetUnReadMsgCount(groupID: user.group_id ?? "", cell: cell) } return cell } 

groupList contains the list of groups which is fetched from firebase on viewWillAppear.

func GetLastMsg(groupID : String, cell : GroupsTableViewCell){ let userRef2 = rootRef2.child("message").child(groupID).queryLimited(toLast: 1) userRef2.observe( .value, with: { snapshot in guard let _ = snapshot.value as? [String:AnyObject] else { print("Error") return } print("children count: \(snapshot.children.allObjects.count)") for snap in snapshot.children.allObjects as! [DataSnapshot] { let message = Message() let value = snap.value as? [String: Any] ?? [:] let text = value["text"] as? String ?? "Name not found" let mimType = value["mimType"] as? String let name_doc = value["name_doc"] as? String ?? "file.file" message.text = text message.mimType = mimType message.name_doc = name_doc message.timestamp_group = (value["timestamp"] as! NSNumber) print(value["idSender"] as? String) print(message.name_doc) var msg_last = "" // cell.lbl_lastmsg.text = msg_last if message.mimType == "image/jpeg" { msg_last = "Image" cell.img_small_width.constant=28 cell.img_small.image = UIImage(named: "im") }else if message.mimType == "audio/3gpp" { msg_last = "Audio" cell.img_small_width.constant=28 cell.img_small.image = UIImage(named: "mi") }else if message.mimType == "video/mp4" { msg_last = "Video" cell.img_small_width.constant=28 cell.img_small.image = UIImage(named: "vi") }else if message.mimType == "application/pdf" { let name_docs = message.name_doc!.split{$0 == "."}.map(String.init) msg_last = name_docs.last! cell.img_small_width.constant=28 cell.img_small.image = UIImage(named: "doc") }else if mimType == nil{ msg_last = message.text! cell.img_small_width.constant=0 } DispatchQueue.main.async { cell.lbl_lastmsg.text = msg_last } } } }) } 

New method:

 func GetUnReadMsgCount(groupID : String, cell : GroupsTableViewCell) { rootRef2.child("group_message_unread").child(current_user!).child(groupID).observe(.childAdded, with: { (snapshot) -> Void in print(snapshot.childrenCount) print(snapshot.children.description) if snapshot.childrenCount > 0 { DispatchQueue.main.async { cell.view_count.isHidden = false cell.lbl_count.text = String(snapshot.childrenCount) // self.tbl_groups.reloadRows(at: [IndexPath(row: 3, section: 0)], with: .fade) // self.tbl_groups.reloadData() } } }) } 

1 Answer 1

1

That's the expected behavior. In a .observe( .value listener, the snapshot is always the complete data at the path. So when you add a child node, the snapshot fires with the entire new data at userRef2.

You have two main options to not get duplicates in your UI:

  1. Clear all messages when there is an update, before adding the data to the table again. So that'd be right before for snap in snapshot.children in your code. This is by far the simplest way to solve the problem if duplicate rows, but may lead to some flashing in your UI.

  2. Listen for child events, instead of observing the entire value. With this you'll get a single .childAdded event for the new child, you can get rid of the for snap in snapshot.children.allObjects and just add the singular new child node to the table.

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you so much for your time. Is that the right way to call the firebase function in the cellforrow method? To test your solution, I have used another method to get the count of the new unread message, and used .childAdded but still when I go inside the chat group and come back If a receive a new message, the message count reflects in other group also. Any idea? I have updated my code. @Frank
Are you reattaching the observer? Because in that case it will indeed refire .childAdded for every child again. If you only want to listen for new messages, you'll need to change the listener for that. Have a look at these question about the topic: stackoverflow.com/…
Yes, I am removing the observer when the screen disappears. Thanks for the link but that's doesn't help me. The problem occurs only when I go inside any chat group and come back then if a new message comes, the last message appearing in multiple cells.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.