【问题标题】:Tableview only updating after I leave the view and come backTableview 仅在我离开视图并返回后才更新
【发布时间】:2017-08-09 09:40:24
【问题描述】:

我正在将 cmets 添加到项目中,并且一切似乎都在工作,但是在我离开屏幕然后再次返回之前,我显示 cmets 的 tableview 没有得到正确更新。

基本上,一旦输入评论并按下“发送”,评论以及评论作者就会发布到 Firebase。然后循环保存这两个值的字典,并且 cmets 进入一个数组,而评论作者进入另一个数组(这样我就可以用数组的 indexPaths 填充我的表视图):

@IBAction func addCommentButtonPressed(_ sender: Any) {

    if addCommentTextField.text != nil {
        if let comment = addCommentTextField.text {
            print(comment)

            let ref = FIRDatabase.database().reference()
            let keyToPost = ref.child("posts").childByAutoId().key

            ref.child("posts").child(self.postID).observeSingleEvent(of: .value, with: { (snapshot) in

                if let post = snapshot.value as? [String : AnyObject] {

                    let updateComments: [String: Any] = ["comments/\(FIRAuth.auth()!.currentUser!.displayName!)" : comment]
                    ref.child("posts").child(self.postID).updateChildValues(updateComments, withCompletionBlock: { (error, reff) in

                        if error == nil {
                            ref.child("posts").child(self.postID).observeSingleEvent(of: .value, with: { (snap) in

                                if let properties = snap.value as? [String: AnyObject] {

                                    if let commentLoop = post["comments"] as? [String : AnyObject] {
                                        for (person, comment) in commentLoop {
                                            self.selectedPost.commentAuthors.append(person)
                                            self.selectedPost.commentText.append(comment as! String)
                                        }
                                    }

                                    DispatchQueue.main.async {
                                        self.tableView.reloadData()
                                    }
                                }
                            })
                        }
                    })
                }
            })
            ref.removeAllObservers()
        }
    }
    addCommentTextField.resignFirstResponder()
    self.addCommentTextField.text = nil
    self.view.endEditing(true)
    self.addCommentView.isHidden = true
}

这就是我的 Firebase 数据库的样子:

我不确定是什么问题。我觉得我在正确的地方打电话给self.tableView.reloadData()。这是我的 fetch 函数(在显示图像的 FeedViewController 中,而不是具有 cmets 的 PhotoDetailController - 通过点击 FeedViewController 中的一张图像可以达到 PhotoDetailController):

func fetchPosts() {

    let ref = FIRDatabase.database().reference()
    ref.child("users").queryOrderedByKey().observe(.value, with: { snapshot in

        let users = snapshot.value as! [String : AnyObject]

        for (_, value) in users {
            // get uid as string
            if let uid = value["uid"] as? String {
                // check to make sure uids match
                if uid == FIRAuth.auth()?.currentUser?.uid {
                    // check for followers
                    if let followingUsers = value["following"] as? [String : String] {
                        // loop through those and add them to "following" array
                        for (_, user) in followingUsers {
                            self.following.append(user)
                        }
                    }
                    // add current user to that array also so you can see your own posts
                    self.following.append(FIRAuth.auth()!.currentUser!.uid)

                    ref.child("posts").queryOrderedByKey().observeSingleEvent(of: .value, with: { (snap) in
                        let postsSnap = snap.value as! [String : AnyObject]

                        for (_, post) in postsSnap {
                            if let userID = post["userID"] as? String {
                                for each in self.following {
                                    if each == userID {
                                        // here are the posts that the user should see (his own and his following)
                                        let posst = Post()
                                        if let author = post["author"] as? String, let likes = post["likes"] as? Int, let pathToImage = post["pathToImage"] as? String, let postID = post["postID"] as? String {

                                            posst.author = author
                                            posst.likes = likes
                                            posst.pathToImage = pathToImage
                                            posst.postID = postID
                                            posst.userID = userID
                                            if let people = post["peopleWhoLike"] as? [String : AnyObject] {
                                                for (_, person) in people {
                                                    posst.peopleWhoLike.append(person as! String)
                                                }
                                            }

                                            if let commentLoop = post["comments"] as? [String : AnyObject] {
                                                for (person, comment) in commentLoop {
                                                    posst.commentAuthors.append(person)
                                                    posst.commentText.append(comment as! String)
                                                }
                                            }

                                            posts.append(posst)
                                        }
                                    }
                                }
                                self.collectionView.reloadData()
                            }
                        }
                    })
                    ref.removeAllObservers()
                }
            }
        }
    })
}

是发表评论后重新加载 tableView 的问题,还是在 fetch 函数中?就像我说的,一切似乎都可以在 firebase 上正常工作,我只想更新包含 cmets 的 tableView,以便在发布后立即显示评论。

编辑:感谢 Jen 的精彩建议。我尝试了您的建议,并进行了一些小改动以消除警告/错误:

@IBAction func addCommentButtonPressed(_ sender: Any) {

    if !addCommentTextField.text!.isEmpty {
        addComment(comment: addCommentTextField.text!)
        observePostComments()
    }
}

func addComment(comment: String) {
    let postsCommentsRef = FIRDatabase.database().reference().child("postComments").child(self.postID)
    var commentData:  [String: String] = [:]
    commentData["userId"] = FIRAuth.auth()!.currentUser!.displayName!
    commentData["comment"] = comment
    postsCommentsRef.childByAutoId().setValue(commentData)
}


func observePostComments() {
    let postsCommentsRef = FIRDatabase.database().reference().child("postComments").child(self.postID)
    postsCommentsRef.observe(.childAdded, with: { snapshot in
        let comment = snapshot.value as! [String: String]
        self.selectedPost.commentAuthors.append(comment["userId"]!)
        self.selectedPost.commentText.append(comment["comment"]!)
        self.tableView.reloadData()
    })
}

这些是我的 tableView 方法:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! CommentCell

    cell.commentAuthorLabel?.text = selectedPost.commentAuthors[indexPath.row]
    cell.commentLabel?.text = selectedPost.commentText[indexPath.row]

    return cell
}

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return selectedPost.commentAuthors.count
}

func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
    return 72
}

【问题讨论】:

  • 在主线程上重新加载表。UI相关任务在主线程上完成。
  • 我尝试将 reloadData 调用包装在 DispatchQueue.main.async 中,但没有帮助。似乎 cmets 也被加载了两次。

标签: ios swift uitableview firebase firebase-realtime-database


【解决方案1】:

看起来fetchPosts 既更新了数据库又监听了变化。我建议你设置一个只更新数据库的函数。然后有一个单独的函数,在视图中调用一次,并使用.observe(.childAdded) 将新的 cmets 附加到 tableView,只要它们出现在数据库中。

编辑: 由于您是 Firebase 新手,以下是一些简化代码和更新 tableView 的具体建议:

在“posts”之外创建一个单独的子项来保存 cmets。有时您可能希望从帖子中访问一些不包括 cmets 的信息,因此最好通过保持数据库平坦来最大限度地减少下载的额外数据量。使用相同的 postId 链接帖子和帖子 cmets。

结果如下所示:

"posts":
    "-postIdKey":
        "photoPath": "..."
        "name": "..."
        "date": "..."
        "...":  "..."          

"postComments:"
     "-postIdKey":
         "-commentIdPush1":
             "userId": "uId1"
             "comment": "Love this pic!"
         "-commentIdPush2":
             "userId": "uId2"
             "comment": "Wow!"
  1. addCommentButtonPressed中,如果文本字段中有文本,调用addComment,将文本作为参数传递。创建一个字典来保存您将传递给 setValue 的数据。设置“userId”和“comment”键的值后,使用 childByAutoId 为 postCommentsRef 创建一个新子项并传递评论数据。

    @IBAction func addCommentButtonPressed(_ sender: Any) {
        if !addCommentTextField.text!.isEmpty {
            addComment(addCommentTextField.text!)
        }
    }
    
    func addComment(comment: String) {
        var commentData:  [String: String] = [:] 
        commentData["userId"] = self.userID
        commentData["comment"] = comment
        postCommentsRef.childByAutoId().setValue(commentData)
    }
    
  2. 不是观察.value 的单个事件,而是通过创建一个观察新 cmets 的侦听器来利用 Firebase 数据库是实时的这一事实。您可以创建另一个仿照此函数的函数来监听新帖子。

    let postsCommentsRef = FIRDatabase.database().reference().child("postComments").child(postID)
    
    func observePostComments() { 
        postsCommentsRef.observe(.childAdded, with: { snapshot in
            let comment = snapshot.value as! [String: String]
            self.comments.append(comment["userId"])
            self.commentAuthors.append(comment["comment"])
            self.yourTableView.insertRows(at: [IndexPath(row: self.comments.count-1, section: 0)], with: .automatic)
    
        })
    }
    

请注意 #2 和 #3 中关注点的分离。 addCommentButtonPressed 只关心向数据库添加新的 cmets。 observePostComments 只关心从数据库中向UITableView 添加新的 cmets。

【讨论】:

  • 谢谢你,这非常有帮助。我花了一些时间自己尝试执行第 1 步,然后才意识到第 2 步和第 3 步做到了,最终删除/覆盖了我所有的 Firebase 节点,这很有趣。但无论如何,我实施了你的建议(并在addCommentButtonPressed中调用observePostComment,在if语句中,对吗?并且还将addComment中的postCommentsRef更改为postsCommentsRef,希望这也是正确的......但是我遇到了关于 tableview 的崩溃。
  • 忽略最后一条消息,我改变了一些东西(我用tableView.reloadData而不是insertRows),现在没有崩溃。我还添加了一个viewDidAppear,我在那里打电话给observePostComments,一切似乎都运行良好!再次感谢这真的很有帮助 - 当您学习如何使用 Firebase 时,它​​非常棒,所以我需要更多的练习,但这是一个很好的参考!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-22
  • 1970-01-01
  • 1970-01-01
  • 2016-12-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多