简体   繁体   中英

Tableview only updating after I leave the view and come back

I'm adding comments to a project and everything seems to be working, however my tableview that displays the comments doesn't get properly updated until I navigate off the screen and then back again.

Basically once a comment is entered and "send" is pressed, the comment, along with the comment author, is posted to Firebase. Then the dictionary that holds those two values is looped through and the comments go into one array, while the comment authors go into another (this is so I can populate my table view with the arrays' 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
}

And this is what my Firebase database looks like:

在此处输入图片说明

I'm not sure what the problem is. I feel like I'm calling self.tableView.reloadData() in the correct place. This is my fetch function (in the FeedViewController , where the images are displayed, not the PhotoDetailController which has the comments - PhotoDetailController is reached by tapping on one of the images in FeedViewController ):

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

Is the issue in the reloading of the tableView once the comment is posted, or is it in the fetch function? Like I said everything seems to be working properly with firebase, I'd just like the tableView which holds the comments to update to show a comment as soon as it's posted.

EDIT: Thanks for the awesome advice Jen.. I tried your suggestions with a few minor changes to get rid of warnings/errors:

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

These are my tableView methods:

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
}

It looks like the fetchPosts both updates the database and listens for changes. I recommend you set up a function that only updates the database. Then have a separate function that is called once in the view and uses .observe(.childAdded) to append new comments to the tableView whenever they appear in the database.

EDIT: Since you are new to Firebase, here are some specific suggestions to simplify the code and update the tableView:

Create a separate child outside of "posts" to hold comments. There may be times where you want to access some information from the post that doesn't include the comments, so it's best to minimize the amount of extra data you download by keeping your database flat. Link the posts and the post comments using the same postId.

The result would look something like this:

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

"postComments:"
     "-postIdKey":
         "-commentIdPush1":
             "userId": "uId1"
             "comment": "Love this pic!"
         "-commentIdPush2":
             "userId": "uId2"
             "comment": "Wow!"
  1. In addCommentButtonPressed , if there is text in the text field, call addComment, passing the text as a parameter. Create a dictionary to hold the data you will pass to setValue. Once you've set the values of the keys "userId" and "comment", create a new child for the postCommentsRef using childByAutoId and passing the comment data.

     @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. Instead of observing a single event of .value , take advantage of the fact that the Firebase Database is realtime by creating a listener that observes for new comments. You can create another function modeled after this one to listen for new posts.

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

Notice the separation of concerns in #2 and #3. addCommentButtonPressed is only concerned with adding new comments to the database. observePostComments is only concerned with adding new comments to the UITableView from the database.

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