user
user

Reputation: 445

Load new messages Swift 4.2 & Firebase

I have created a messaging system for my app and am paginating the messages within the chat log but I'm having an issue that if a new message is sent the user will have to leave the screen and re open the controller to view the new messages they have sent/received. I have tried to reload the collection view and observe the messages again with no luck. Any help is appreciated.

Observing the messages. With Pagination. (working great! On initial load.)

var messages =  [Message]()
fileprivate func observeMessages() {

    guard let uid = Auth.auth().currentUser?.uid else { return }
    guard let userId = user?.uid else { return }

    if currentKey == nil {

        let userMessageRef = Database.database().reference().child("user-message").child(uid).child(userId).queryLimited(toLast: 10).observeSingleEvent(of: .value) { (snapshot) in

            guard let first = snapshot.children.allObjects.first as? DataSnapshot else { return }
            guard var allObjects = snapshot.children.allObjects as? [DataSnapshot] else { return }

            allObjects.forEach({ (snapshot) in

                let messageId = snapshot.key

                let ref = Database.database().reference().child("messages").child(messageId)
                ref.observe(.value, with: { (snapshot) in

                    guard let dict = snapshot.value as? [String: Any] else { return }

                    let message = Message(dictionary: dict)

                    self.messages.append(message)
                    self.messages.sort(by: { (message1, message2) -> Bool in
                        return message1.timeStamp.compare(message2.timeStamp) == .orderedDescending
                    })
                    self.collectionView?.reloadData()
                })
            })

            self.currentKey = first.key
        }

    } else {

        let userMessageRef = Database.database().reference().child("user-message").child(uid).child(userId).queryOrderedByKey().queryEnding(atValue: self.currentKey).queryLimited(toLast: 4).observeSingleEvent(of: .value) { (snapshot) in

            guard let first = snapshot.children.allObjects.first as? DataSnapshot else { return }
            guard var allObjects = snapshot.children.allObjects as? [DataSnapshot] else { return }

            allObjects.forEach({ (snapshot) in

                if snapshot.key != self.currentKey {

                    let messageId = snapshot.key

                    let ref = Database.database().reference().child("messages").child(messageId)
                    ref.observe(.value, with: { (snapshot) in
                        guard let dict = snapshot.value as? [String: Any] else { return }

                        let message = Message(dictionary: dict)

                        self.messages.append(message)
                        self.messages.sort(by: { (message1, message2) -> Bool in
                            return message1.timeStamp.compare(message2.timeStamp) == .orderedDescending
                        })
                        self.collectionView?.reloadData()
                    })
                }
            })
            self.currentKey = first.key

        }
    }
}

Upvotes: 0

Views: 485

Answers (2)

TJMac
TJMac

Reputation: 159

The way I set mine up was to call the function in viewDidLoad and then again in viewDidAppear. I'm still learning as well, but you may want to try that, it would probably look something like this:

override func viewDidLoad() {
    super.viewDidLoad()

    observeMessages(for: userID) { (messages) in
        self.messages = messages
        self.collectionView.reloadData()
    }
}

And again in viewDidAppear:

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)

    observeMessages(for: userID) { (messages) in
        self.messages = messages
        self.collectionView.reloadData()
    }
}

Upvotes: 0

qtngo
qtngo

Reputation: 1679

From Firebase database documentation

In some cases you may want a callback to be called once and then immediately removed, such as when initializing a UI element that you don't expect to change. You can use the observeSingleEventOfType method to simplify this scenario: the event callback added triggers once and then does not trigger again.

I suggest you to change to observeEventType:withBlock whichs allow you to observe all changes events.

Hope this helps.

Upvotes: 1

Related Questions