Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/96.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 在TableView单元格中处理从Firebase检索数据的更好方法_Ios_Swift_Firebase_Google Cloud Firestore - Fatal编程技术网

Ios 在TableView单元格中处理从Firebase检索数据的更好方法

Ios 在TableView单元格中处理从Firebase检索数据的更好方法,ios,swift,firebase,google-cloud-firestore,Ios,Swift,Firebase,Google Cloud Firestore,在我的聊天功能中,我在tableview中向当前用户显示他与其他用户的聊天记录。tableview上的每个单元格都是对方用户的信息、化身和姓名。将这些信息存储在聊天对象中很容易,但问题是,对方用户可能在此时更改了他的化身或姓名 因此,我在聊天室的手机配置中获取对方用户的头像和姓名。它工作得很好,但我不确定是否有更好的方法,因为我不赞成在每个单元中进行Firebase网络呼叫 以下是我的单元配置方法: func configureCell(from chat: Chat){ //

在我的聊天功能中,我在tableview中向当前用户显示他与其他用户的聊天记录。tableview上的每个单元格都是对方用户的信息、化身和姓名。将这些信息存储在聊天对象中很容易,但问题是,对方用户可能在此时更改了他的化身或姓名

因此,我在聊天室的手机配置中获取对方用户的头像和姓名。它工作得很好,但我不确定是否有更好的方法,因为我不赞成在每个单元中进行Firebase网络呼叫

以下是我的单元配置方法:

    func configureCell(from chat: Chat){
    // 1st Get opposite user id
    if let currentUser = Auth.auth().currentUser{
        let user1 = chat.people.first
        let user2 = chat.people.last
        let user1Id = user1?["id"] ?? ""
        let user2Id = user2?["id"] ?? ""
        var oppositeUserId = ""
        if user1Id == currentUser.uid{
            oppositeUserId = user2Id
        }else{
            oppositeUserId = user1Id
        }
        //2nd Fetch opposite user doc
        let oppositeUserDocRef = References.Instance.getUserDocRef(for: oppositeUserId)
        oppositeUserDocRef.getDocument { (oppositeUserDocSnapshot, error) in
            if error != nil{
                print("ERROR FETCHING OPPOSITE USER DOC:: ERROR IS:  \(error?.localizedDescription ?? "")")
                return
            }
            // 3rd get opposite user avatar url and name
            if let otherUserDic = oppositeUserDocSnapshot?.data(){
                if let avatarDic = otherUserDic["avatar"] as? [String: String]{
                    let avatarUrl = avatarDic["url"] ?? ""
                    self.avatarView.sd_setImage(with: URL(string: avatarUrl),
                                          placeholderImage: nil, options: .refreshCached)
                }
                if let name = otherUserDic["name"] as? String{
                    self.uiLabelChatTitle.text = name
                }
            }
        }
    }
}

我从未真正使用过Firebase,但对于类似的东西,我会说在一个网络请求中填充一个“chatDetails”对象数组,然后配置每个可重用单元

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

        let chat = self.chatDetails[indexPath.row]

        let cell = tableView.dequeueReusableCell(withIdentifier: "identifier") as! ChatDetailsCell

        cell.configureCell(chat: chat)

        return cell

    }

正如他们在评论中所建议的那样,预取数据将是一个更好的解决方案。这很棘手,取决于每个应用程序的细节。我的目标是模仿WhatsApp的聊天列表功能,实时更新用户信息

以下是我为实现这一目标所做的:

    func showChats(){
    guard let currentUser = Auth.auth().currentUser else{
        return
    }
    let profileController = UserProfileController.instance
    if let snapshot = profileController.chats{
        for document in snapshot.documents{
            let chat = ChatController.instance.getChat(from: document)
            chats.append(chat)
            print("GOT CHAT:::: \(document.data())")
        }
        tableview.reloadData()
    }
    else{
        print("NOTHING IN INBOX!!!!")
    }
    // Attach listeners to chat users docs to listen for change in avatars and names
    // 1st: Loop through each chat to get people and know opposite user id
    for (i, var chat) in chats.enumerated(){
        let person1 = chat.people.first
        let person2 = chat.people.last
        let person1Id = person1?["id"] ?? ""
        let person2Id = person2?["id"] ?? ""
        var oppositeUserId = ""
        var opposteUsrIsPerson1 = false
        if person1Id == currentUser.uid{
            oppositeUserId = person2Id
            opposteUsrIsPerson1 = false
        }
        else{
            oppositeUserId = person1Id
            opposteUsrIsPerson1 = true
        }
        // 2nd: Fetch opposite user doc and add listener to it
        let oppositeUserDocRef = References.Instance.getUserDocRef(for: oppositeUserId)
        let docListener = oppositeUserDocRef.addSnapshotListener { (oppositeUserDocSnapshot, error) in
            if error != nil {
                print("ERROR FETCHING OTHER PERSON DOC:: ERROR IS:  \(error?.localizedDescription ?? "")")
                return
            }
            // 3rd: get other user avatar url and name from his doc
            if let oppositeUserDic = oppositeUserDocSnapshot?.data(){
                var avatarUrl = ""
                var name = ""
                if let avatarDic = oppositeUserDic["avatar"] as? [String: String]{
                    avatarUrl = avatarDic["url"] ?? ""
                }
                if let oppositeUsrName = oppositeUserDic["name"] as? String{
                    name = oppositeUsrName
                }
                // 4th: Create ChatPerson object with the fetched values and replace the existing one
                let chatPerson = ChatPerson(id: oppositeUserId, name: name, avatarUrl: avatarUrl)
                if opposteUsrIsPerson1{
                    chat.people[0] = chatPerson.toDictionalry()
                }
                else{
                    chat.people[1] = chatPerson.toDictionalry()
                }
                // 5th: Update data and reload the chat row
                self.chats[i] = chat
                let indexpath = IndexPath(row: i, section: 0)
                self.tableview.reloadRows(at: [indexpath], with: .automatic)
            }
        }
        //6th: Add doc listener to liteners list to remove it later in deinit()
        chatUserListeners.append(docListener)
    }
}
在视图控制器的deinit()循环中,通过侦听器删除它们:

    deinit {
    for listener in chatUserListeners{
        listener.remove()
    }
}

问题是我需要从每个文档中获取每个相反用户的姓名和头像。我可以在第一次创建聊天对象时输入这些信息,但对方用户可能在某个时候更改了自己的姓名或头像,在这种情况下,聊天对象信息将过时那么,如果对方用户在每个小区配置完毕后更改了他们的姓名或化身呢?该更改不会反映在表视图中。因此,无论您是同时获取每个单元格的所有数据,还是单独获取每个单元格的所有数据,您都必须调用reloadData方法。为了澄清这一点,Firebase有观察者监视数据库的更改。当发生更改时,它会向应用程序通知包含更改数据的事件。firebase observer代码闭包将使用新信息更新tableView数据源,并且可以仅重新加载tableView中的该行,或者如您所述重新加载所有行。如果firebase具有此功能,这显然是正确的选择。感谢各位的建议,我用监听器来监听每个聊天室用户的变化,并发布了我的答案。我不赞成在每个手机中拨打Firebase网络电话。真为你高兴。你说得对。请不要这样做,它可能是滞后的,有时给用户一个糟糕的体验。TableView是为高性能而设计的,因此工作越少越好。您应该使用tableView的数据预填充tableView数据源。然后将观察者连接到存储/跟踪用户化身的节点,并观察其变化。发生更改时,观察员应使用新信息更新tableView数据源,然后刷新tableView。感谢您的建议。我认为性能不会有问题,因为Firebase调用是在后台进行的。我更担心的是,我的列表在填充之前会在每个单元格中不断进行网络呼叫,这在金钱上是很昂贵的。我得想个办法。预取可以工作,但很棘手,因为可能会有很多聊天,我需要遍历每个聊天用户来获取他的数据。我认为他们使用批处理函数来实现for循环中的调用。我找到了答案并发布了我的答案,谢谢你的建议。