简体   繁体   中英

CollectionView: scrollToItem, reloadData, and Dispatch Queues

Good afternoon all,

I'm encountering a frustrating bug regarding a chatting application tutorial I've been following, and would like to remedy (the tutorial doesn't address this problem since I have converted to Swift 3 / Xcode8). Let me try to describe the problem:

A chat log between two users utilizes Firebase Database to store and retrieve the conversation messages between them. I am using a collectionView to display the conversation. I wanted to implement a feature in the chat log, such that when a user selects a conversation to view, it would scroll to the latest/last "message" for the user to easily continue the conversation.

Here is the current relevant code of the chat log controller:

func observeMessages() {
    guard let uid = FIRAuth.auth()?.currentUser?.uid, let toId = user?.id else {
        return
    }

    let userMessagesRef = FIRDatabase.database().reference().child("user-messages").child(uid).child(toId)
    userMessagesRef.observe(.childAdded, with: { (snapshot) in

        let messageId = snapshot.key
        let messagesRef = FIRDatabase.database().reference().child("messages").child(messageId)
        messagesRef.observeSingleEvent(of: .value, with: { (snapshot) in

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

            self.messages.append(Message(dictionary: dictionary))

            DispatchQueue.main.async(execute: {
                self.collectionView?.reloadData()

                let indexPath = IndexPath(item: self.messages.count - 1, section: 0)

                self.collectionView?.scrollToItem(at: indexPath, at: .bottom, animated: true)
            })

        }, withCancel: nil)

    }, withCancel: nil)
}

The problem I'm encountering is in regards to an invalid indexPath for the collectionView to scroll to. Using print statements, I have found that reloadData() gets called a lot, and it is simply my assumption from the debug console that indexPath cannot "update" or "keep up" with the values.

I am quite new to GCD (I've only been told updates to UI should always be done on the main thread), and was wondering if the answer to my problem would lie within setting up proper synchronous/asynchronous execution, or serial/concurrent queues.

Ex// Use a background thread to fetch the conversation messages and update indexPath, while the main thread asynchronously reloadsData and scrollsToItem.

I'm not sure, but if someone could shed some light on this, or point me in the right direction, I'd really appreciate it. Much thanks.

If your collectionView based on

self.messages array, 

put

self.messages.append(Message(dictionary: dictionary)) 

into main thread too.

All your data lists that used for main thread tables (collectionView or tableView) must be managed on main thread only.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM