CollectionView:scrollToItem,reloadData和Dispatch Queues

时间:2016-11-08 03:43:53

标签: swift swift3 grand-central-dispatch reloaddata collectionview

下午好,

我遇到了一个关于我一直关注的聊天应用程序教程的令人沮丧的错误,并且想要补救(由于我已经转换为Swift 3 / Xcode8,教程没有解决这个问题)。让我试着描述一下这个问题:

两个用户之间的聊天记录使用Firebase数据库来存储和检索它们之间的对话消息。我正在使用collectionView来显示对话。我想在聊天记录中实现一项功能,这样当用户选择要查看的对话时,它会滚动到最新/最后一条“消息”,以便用户轻松地继续对话。

以下是聊天记录控制器的当前相关代码:

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)
}

我遇到的问题是关于collectionView滚动到的无效indexPath。使用print语句,我发现reloadData()被调用很多,而我只是从调试控制台假设indexPath不能“更新”或“跟上”这些值。

我对GCD很新(我只是被告知UI的更新应该总是在主线程上完成),并且想知道我的问题的答案是否在于设置正确的同步/异步执行,或者串行/并发队列。

Ex //使用后台线程获取对话消息并更新indexPath,而主线程异步reloadsData和scrollsToItem。

我不确定,但是如果有人可以对此有所了解,或者指出我正确的方向,我真的很感激。非常感谢。

1 个答案:

答案 0 :(得分:1)

如果你的collectionView基于

self.messages array, 

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

也进入主线程。

用于主线程表(collectionView或tableView)的所有数据列表必须仅在主线程上进行管理。