调用注释来填充TableView:更正代码错误 [英] Calling Comments to Populate a TableView: correcting code errors

查看:56
本文介绍了调用注释来填充TableView:更正代码错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试用我的帖子中的评论填充我的commentsTable.我具有以下数据库结构JSON:

  {
  "posts" : {
    "-Lhu-XRs806sXSEQS2BF" : {
      "reports" : 0,
      "text" : "How can I improve my data structure?",
      "timestamp" : 1561120090116,
      "title" : "Hello Stack Exchange",
      "userID" : "nyRBXSyyDhc1Qkypou0Iz0iMsyr1"
    },
    "-Lhu-fI6DMSZvy8EdIgM" : {
      "reports" : 0,
      "text" : "As in Libre",
      "timestamp" : 1561120126347,
      "title" : "Free",
      "userID" : "nyRBXSyyDhc1Qkypou0Iz0iMsyr1"
    },
    "comments" : {
      "-Lhu-hXISy-0N2V4ES-a" : {
        "reports" : 0,
        "timestamp" : 1561120135594,
        "userID" : "nyRBXSyyDhc1Qkypou0Iz0iMsyr1"
      },
      "-Lhu-j1cR6V407tyUYY1" : {
        "reports" : 0,
        "timestamp" : 1561120141801,
        "userID" : "nyRBXSyyDhc1Qkypou0Iz0iMsyr1"
      },
      "-Lhu-lrJp9H8SQowlYWz" : {
        "reports" : 0,
        "timestamp" : 1561120153314,
        "userID" : "nyRBXSyyDhc1Qkypou0Iz0iMsyr1"
      },
      "posts" : {
        "-Lhu-XRs806sXSEQS2BF" : {
          "comments" : {
            "-Lhu-hXISy-0N2V4ES-_" : "How is it going?",
            "-Lhu-j1cR6V407tyUYY0" : "It’s good to see you"
          }
        },
        "-Lhu-fI6DMSZvy8EdIgM" : {
          "comments" : {
            "-Lhu-lrJp9H8SQowlYWy" : "Richard Stallman"
          }
        }
      }
    }
  }
}

以及以下注释类:

class Comment {
    var id:String
    var text:String

    init(id: String, text:String) {
        self.id = id
        self.text = text
    }
}

考虑到您的建议后,这是我的代码:

var comments = [Comment] ()
@IBOutlet weak var commentsTable: UITableView!
@IBOutlet weak var commentPlaceHolder: UILabel!
@IBOutlet weak var newCommentLabel: UITextView!
weak var delegate:NewPostVCDelegate?
let ref = Database.database().reference().child("posts")

@IBAction func reply(_ sender: UIButton) {
    let userID = (Auth.auth().currentUser?.uid)!
    addComment(toPostId: post!.id, andComment: newCommentLabel.text, commentByUid: userID)
    loadComments(forPostId: post!.id)
    comments.removeAll()
    commentsTable.reloadData()
    newCommentLabel.text = String()
    commentPlaceHolder.isHidden = false
}

func addComment(toPostId: String, andComment: String, commentByUid: String) {
    let commentsRef = self.ref.child("comments") //ref to the comments node
    let thisCommentRef = commentsRef.child(toPostId) //ref to a node with postId as key
    let commentToAddRef = thisCommentRef.childByAutoId() //each comment will have it's own key
    let d = [
        "comment_text": andComment,
        "comment_by_uid": commentByUid]
    commentToAddRef.setValue(d)
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    loadComments(forPostId: post!.id)
}

func loadComments(forPostId: String) {
    let ref = self.ref.child("comments")
    let thisPostRef = ref.child(forPostId)
    thisPostRef.observeSingleEvent(of: .value, with: { snapshot in

        let allComments = snapshot.children.allObjects as! [DataSnapshot]
        for commentSnap in allComments {
            let commenterUid = commentSnap.childSnapshot(forPath: "comment_by_uid").value as? String ?? "No uid"
            let commentText = commentSnap.childSnapshot(forPath: "comment_text").value as? String ?? "No comment"
            let aComment = Comment(id: commenterUid, text: commentText)
            self.comments.append(aComment)
            print(commenterUid, commentText)
        }
        self.commentsTable.reloadData()
    })
}

func adjustUITextViewHeight(arg : UITextView) {
    arg.translatesAutoresizingMaskIntoConstraints = true
    arg.sizeToFit()
    arg.isScrollEnabled = false
}

override func viewDidLoad() {
    super.viewDidLoad()
    self.commentsTable.dataSource = self
    let cellNib = UINib(nibName: "CommentTableViewCell", bundle: nil)
    commentsTable.register(cellNib, forCellReuseIdentifier: "postCell")
    view.addSubview(commentsTable)
    commentsTable.register(LoadingCell.self, forCellReuseIdentifier: "loadingCell")

    self.commentsTable.delegate = self
    mainText.isEditable = false
    titleText.isEditable = false
    commentsTable.register(cellNib, forCellReuseIdentifier: "postCell")
    view.addSubview(commentsTable)
    commentsTable.register(LoadingCell.self, forCellReuseIdentifier: "loadingCell")
    print(delegate!)
}

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

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    if indexPath.section == 0 {
        let cell = tableView.dequeueReusableCell(withIdentifier: "postCell", for: indexPath) as! CommentTableViewCell
        cell.set(comment: comments[indexPath.row])
        return cell
    } else {
        let cell = tableView.dequeueReusableCell(withIdentifier: "loadingCell", for: indexPath) as! LoadingCell
        cell.spinner.startAnimating()
        return cell
    }
}

func textViewDidChange(_ commentView: UITextView) {
    commentPlaceHolder.isHidden = !newCommentLabel.text.isEmpty
}

结合杰伊(Jay)的评论,使视图运行起来.我必须添加comments.removAll(),因此它没有在commentsTable中多次打印出注释.但是,func textViewDidChange不再起作用.我不确定该如何解决.我试过没有运气调用该函数.也许代表变更影响了这一点?

解决方案

此答案基于问题中的数据,然后基于后续注释.

对数据进行非规范化是NoSQL数据库中的标准做法,但在这种情况下,问题中的结构可能比所需的更为复杂.

这是问题

给出一系列帖子,每个帖子都有评论,您如何加载 每个帖子的评论都将显示在tableView中.

我将从拟议的结构开始进行反向工作

posts
   post_0 //created with .childByAutoId
      creator_uid: "the uid of whoever created this post"
      post_title: "My post about posting"

comments
   post_0 //ties back to the key of the post in the posts node
      comment_0 //created with .childByAutoId
         comment_by_uid: "whoever created this comment"
         comment_text: "comment about this post"
      comment_1
         comment_by_uid: "whoever created this comment"
         comment_text: "comment about this post"

此结构将评论从引用的帖子中分离出来.在comment节点内,每个节点的关键字是posts节点中的post_id.这样一来,无需过多开销即可将帖子加载到tableView中,例如,如果您要在detailView中显示评论,请加载特定帖子的所有评论.

请注意,发布节点和评论节点键是使用.childByAutoId()

创建的

现在是工作流程.假设用户正在创建新帖子,并且已经输入了该帖子的标题和其他信息.调用它以在Firebase中创建帖子.

func createPost(withTitle: String, andCreatorUid: String) {
    let postsRef = self.ref.child("posts")
    let thisPost = postsRef.childByAutoId()
    let d = [
        "post_title": withTitle,
        "creator_uid": andCreatorUid
        ]
    thisPost.setValue(d)
}

这是一个棘手的问题-我要做的是有posts节点的观察者的.添加新帖子后,我收到该事件,创建一个包含有关该帖子的信息的PostsClass对象,并将其添加到我的dataSource数组中,然后刷新我的tableView.通过这样做,我还获得了节点的密钥(该节点是使用.childByAutoId创建的).

另一个用户看到了该帖子并想对此发表评论,因此他们点击该帖子以输入评论.以下代码将其注释存储在Firebase中.

func addComment(toPostId: String, andComment: String, commentByUid: String) {
    let commentsRef = self.ref.child("comments") //ref to the comments node
    let thisCommentRef = commentsRef.child(toPostId) //ref to a node with postId as key
    let commentToAddRef = thisCommentRef.childByAutoId() //each comment will have it's own key
    let d = [
        "comment_text": andComment,
        "comment_by_uid": commentByUid]
    commentToAddRef.setValue(d)
}

toPostId是帖子的键,该帖子是从他们选择向其添加评论的PostClass对象获得的.

最后,要专门回答这个问题,这里是针对特定帖子的评论.

func loadComments(forPostId: String) {
    let ref = self.ref.child("comments")
    let thisPostRef = ref.child(forPostId)
    thisPostRef.observeSingleEvent(of: .value, with: { snapshot in

        let allComments = snapshot.children.allObjects as! [DataSnapshot]
        for commentSnap in allComments {
            let commenterUid = commentSnap.childSnapshot(forPath: "comment_by_uid").value as? String ?? "No uid"
            let commentText = commentSnap.childSnapshot(forPath: "comment_text").value as? String ?? "No comment"
            //create a commentClass object, update properties and add to dataSourceArray
            print(commenterUid, commentText)
        }
        //tableView reload
    })
}

注意:

我有一个var类, ref ,因此self.ref指向我的根Firebase节点.您需要将其设置为指向您的

我在此答案中使用post_0和comment_0作为节点密钥名称,因为它比.emB.AutoBidAutoId实际上会在您的Firebase中创建的密钥 -LhzJD3tPL0xcnUDMaOZ 更易于阅读和理解. /p>

I am trying to populate a my commentsTable with the comments from my posts. I have the following Database structure JSON:

  {
  "posts" : {
    "-Lhu-XRs806sXSEQS2BF" : {
      "reports" : 0,
      "text" : "How can I improve my data structure?",
      "timestamp" : 1561120090116,
      "title" : "Hello Stack Exchange",
      "userID" : "nyRBXSyyDhc1Qkypou0Iz0iMsyr1"
    },
    "-Lhu-fI6DMSZvy8EdIgM" : {
      "reports" : 0,
      "text" : "As in Libre",
      "timestamp" : 1561120126347,
      "title" : "Free",
      "userID" : "nyRBXSyyDhc1Qkypou0Iz0iMsyr1"
    },
    "comments" : {
      "-Lhu-hXISy-0N2V4ES-a" : {
        "reports" : 0,
        "timestamp" : 1561120135594,
        "userID" : "nyRBXSyyDhc1Qkypou0Iz0iMsyr1"
      },
      "-Lhu-j1cR6V407tyUYY1" : {
        "reports" : 0,
        "timestamp" : 1561120141801,
        "userID" : "nyRBXSyyDhc1Qkypou0Iz0iMsyr1"
      },
      "-Lhu-lrJp9H8SQowlYWz" : {
        "reports" : 0,
        "timestamp" : 1561120153314,
        "userID" : "nyRBXSyyDhc1Qkypou0Iz0iMsyr1"
      },
      "posts" : {
        "-Lhu-XRs806sXSEQS2BF" : {
          "comments" : {
            "-Lhu-hXISy-0N2V4ES-_" : "How is it going?",
            "-Lhu-j1cR6V407tyUYY0" : "It’s good to see you"
          }
        },
        "-Lhu-fI6DMSZvy8EdIgM" : {
          "comments" : {
            "-Lhu-lrJp9H8SQowlYWy" : "Richard Stallman"
          }
        }
      }
    }
  }
}

And the following Comment class:

class Comment {
    var id:String
    var text:String

    init(id: String, text:String) {
        self.id = id
        self.text = text
    }
}

Here is my code after taking your suggestions into account:

var comments = [Comment] ()
@IBOutlet weak var commentsTable: UITableView!
@IBOutlet weak var commentPlaceHolder: UILabel!
@IBOutlet weak var newCommentLabel: UITextView!
weak var delegate:NewPostVCDelegate?
let ref = Database.database().reference().child("posts")

@IBAction func reply(_ sender: UIButton) {
    let userID = (Auth.auth().currentUser?.uid)!
    addComment(toPostId: post!.id, andComment: newCommentLabel.text, commentByUid: userID)
    loadComments(forPostId: post!.id)
    comments.removeAll()
    commentsTable.reloadData()
    newCommentLabel.text = String()
    commentPlaceHolder.isHidden = false
}

func addComment(toPostId: String, andComment: String, commentByUid: String) {
    let commentsRef = self.ref.child("comments") //ref to the comments node
    let thisCommentRef = commentsRef.child(toPostId) //ref to a node with postId as key
    let commentToAddRef = thisCommentRef.childByAutoId() //each comment will have it's own key
    let d = [
        "comment_text": andComment,
        "comment_by_uid": commentByUid]
    commentToAddRef.setValue(d)
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    loadComments(forPostId: post!.id)
}

func loadComments(forPostId: String) {
    let ref = self.ref.child("comments")
    let thisPostRef = ref.child(forPostId)
    thisPostRef.observeSingleEvent(of: .value, with: { snapshot in

        let allComments = snapshot.children.allObjects as! [DataSnapshot]
        for commentSnap in allComments {
            let commenterUid = commentSnap.childSnapshot(forPath: "comment_by_uid").value as? String ?? "No uid"
            let commentText = commentSnap.childSnapshot(forPath: "comment_text").value as? String ?? "No comment"
            let aComment = Comment(id: commenterUid, text: commentText)
            self.comments.append(aComment)
            print(commenterUid, commentText)
        }
        self.commentsTable.reloadData()
    })
}

func adjustUITextViewHeight(arg : UITextView) {
    arg.translatesAutoresizingMaskIntoConstraints = true
    arg.sizeToFit()
    arg.isScrollEnabled = false
}

override func viewDidLoad() {
    super.viewDidLoad()
    self.commentsTable.dataSource = self
    let cellNib = UINib(nibName: "CommentTableViewCell", bundle: nil)
    commentsTable.register(cellNib, forCellReuseIdentifier: "postCell")
    view.addSubview(commentsTable)
    commentsTable.register(LoadingCell.self, forCellReuseIdentifier: "loadingCell")

    self.commentsTable.delegate = self
    mainText.isEditable = false
    titleText.isEditable = false
    commentsTable.register(cellNib, forCellReuseIdentifier: "postCell")
    view.addSubview(commentsTable)
    commentsTable.register(LoadingCell.self, forCellReuseIdentifier: "loadingCell")
    print(delegate!)
}

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

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    if indexPath.section == 0 {
        let cell = tableView.dequeueReusableCell(withIdentifier: "postCell", for: indexPath) as! CommentTableViewCell
        cell.set(comment: comments[indexPath.row])
        return cell
    } else {
        let cell = tableView.dequeueReusableCell(withIdentifier: "loadingCell", for: indexPath) as! LoadingCell
        cell.spinner.startAnimating()
        return cell
    }
}

func textViewDidChange(_ commentView: UITextView) {
    commentPlaceHolder.isHidden = !newCommentLabel.text.isEmpty
}

Incorporating Jay's comments, I got the view running. I had to add comments.removAll() so it did not print out the comments multiple times in the commentsTable. However, the func textViewDidChange no longer functions. I am not sure how to address this. I tried calling the function with no luck. Maybe the delegate change affected this?

解决方案

This answer is based on data in the question and then followup comments.

Denormalizing data is standard practice in NoSQL databases but in this case the structure in the question may be more complex than is needed.

Here's the question

Given a series of posts where each post has comments, how do you load the comments for each post to be displayed in a tableView.

I am going to work backward from a proposed structure

posts
   post_0 //created with .childByAutoId
      creator_uid: "the uid of whoever created this post"
      post_title: "My post about posting"

comments
   post_0 //ties back to the key of the post in the posts node
      comment_0 //created with .childByAutoId
         comment_by_uid: "whoever created this comment"
         comment_text: "comment about this post"
      comment_1
         comment_by_uid: "whoever created this comment"
         comment_text: "comment about this post"

This structure separates out the comments from the post they reference. Within the comments node, the key to each node is the post_id from the posts node. This allows the posts to be loaded in a tableView without a lot of overhead and if for example, you're displaying the comments in a detailView, load all of the comments for a specific post.

Note that posts nodes and comments node keys are created with .childByAutoId()

Now the workflow. Suppose a user is creating a new post and has entered a title for the post and other information. Call this to create the post in Firebase.

func createPost(withTitle: String, andCreatorUid: String) {
    let postsRef = self.ref.child("posts")
    let thisPost = postsRef.childByAutoId()
    let d = [
        "post_title": withTitle,
        "creator_uid": andCreatorUid
        ]
    thisPost.setValue(d)
}

Here's the tricky bit - what I do is have an observer of the posts node. When a new post is added, I receive that event, create a PostsClass object that contains info about the post and add that to my dataSource array, then refresh my tableView. By doing that, I am also getting the key to the node (which was created with .childByAutoId).

Another user sees that post and wants to comment on it so they tap the post to enter a comment. The follow code stores their comment in Firebase.

func addComment(toPostId: String, andComment: String, commentByUid: String) {
    let commentsRef = self.ref.child("comments") //ref to the comments node
    let thisCommentRef = commentsRef.child(toPostId) //ref to a node with postId as key
    let commentToAddRef = thisCommentRef.childByAutoId() //each comment will have it's own key
    let d = [
        "comment_text": andComment,
        "comment_by_uid": commentByUid]
    commentToAddRef.setValue(d)
}

toPostId is the key to the post which is obtained from the PostClass object they selected to add a comment to.

Finally, to specially answer the question, here's the loading of comments for a specific post.

func loadComments(forPostId: String) {
    let ref = self.ref.child("comments")
    let thisPostRef = ref.child(forPostId)
    thisPostRef.observeSingleEvent(of: .value, with: { snapshot in

        let allComments = snapshot.children.allObjects as! [DataSnapshot]
        for commentSnap in allComments {
            let commenterUid = commentSnap.childSnapshot(forPath: "comment_by_uid").value as? String ?? "No uid"
            let commentText = commentSnap.childSnapshot(forPath: "comment_text").value as? String ?? "No comment"
            //create a commentClass object, update properties and add to dataSourceArray
            print(commenterUid, commentText)
        }
        //tableView reload
    })
}

Notes:

I have a class var, ref, so self.ref points to my root firebase node. You will need to set that to point to yours

I am using post_0, and comment_0 as node key names in this answer as it's easier to read and understand than a key like -LhzJD3tPL0xcnUDMaOZ which is what .childByAutoId will actually create in your firebase.

这篇关于调用注释来填充TableView:更正代码错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆