【问题标题】:Calling Comments to Populate a TableView: correcting code errors调用注释来填充 TableView:更正代码错误
【发布时间】:2019-11-04 01:40:08
【问题描述】:

我正在尝试用我帖子中的 cmets 填充我的 cmetsTable。我有以下数据库结构 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 的 cmets,我可以运行视图。我必须添加 cmets.removAll(),这样它就不会在 cmetsTable 中多次打印出 cmets。但是,func textViewDidChange 不再起作用。我不知道如何解决这个问题。我尝试调用该函数没有运气。也许委托变更会影响到这一点?

【问题讨论】:

  • 你的主要问题是let comment = Comment(id: childDataSnapshot.key, text: comments) 你应该通过text 而不是comments
  • 我不知道如何调用每个评论文本,因为每个评论文本都与一个唯一 ID 相关联,例如“-Lht1KEhkJR7ZPTcDqn8”或“-Lht1M76Bu9kTXJDezPp”
  • 我删除了我的答案。除了错误之外,整个 JSON 解析都无法正常工作,例如 JSON 中根本没有 id 键。目前还不清楚用户 ID 与 -Lht... 字典键的关系。
  • @RyanSchiller,在您的代码中,let text = dict["comments"] as? [String:Any] 部分的作用是什么?我想这是你的文字。注意:我假设您解析的部分是正确的。
  • 在代码中将 let comment = Comment(id: childDataSnapshot.key, text: comments) 替换为 let comment = Comment(id: childDataSnapshot.key, text: text)。那应该可以。

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


【解决方案1】:

Comment(id: childDataSnapshot.key, text: comments) 这一行中,您正在传递 cmets(它是数组属性),但您需要传递文本。要重新加载数据,请使用 commentsTable.reloadData()。 对于cellForRowAt 中的错误,请仔细检查您需要传递什么来配置您的单元格并检查您在set(comment 中传递的类型是什么

【讨论】:

  • 我不确定如何调用每个评论文本,因为每个评论文本都与一个唯一的 ID 相关联,例如“-Lht1KEhkJR7ZPTcDqn8”或“-Lht1M76Bu9kTXJDezPp”
  • 创建像 [uniqueId: comment text] 这样的字典,然后按键搜索。类似 set(text: cmetsDicrionary[uniqueId])
  • 我认为这需要重组我的 JSON。我尝试使用 comment = [Comment] () 来做到这一点,但我仍然无法弄清楚如何自己提取文本字符串,而不是将 cmets 作为一种类型。
【解决方案2】:

此答案基于问题中的数据,然后跟进 cmets。

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

问题来了

给定一系列帖子,每个帖子都有 cmets,你如何加载 每个帖子的 cmets 都将显示在 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"

这种结构将 cmets 与它们引用的帖子分开。在 cmets 节点中,每个节点的键是来自 posts 节点的 post_id。这允许将帖子加载到 tableView 中而无需大量开销,例如,如果您在 detailView 中显示 cmets,则加载特定帖子的所有 cmets。

请注意,posts 节点和 cmets 节点键是使用 .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)
}

这是一个棘手的问题 - 我所做的 是有一个帖子节点的观察者。添加新帖子时,我会收到该事件,创建一个包含帖子信息的 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 对象获得的帖子的键。

最后,专门回答这个问题,这里是针对具体帖子的cmets的加载。

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 作为节点键名,因为它比 -LhzJD3tPL0xcnUDMaOZ 之类的键更容易阅读和理解,而 .childByAutoId 将在您的 Firebase 中实际创建。

【讨论】:

  • 数据结构看起来不错。我在底部用我当前的代码更新了帖子。 tableView 仍然不会加载 cmets。现在,当我输入 newCommentLabel textView 时,我的 commentPlaceHolder 不会消失。我的数据源或视图加载有问题吗?我的调试尝试尚未产生任何结果。
  • @RyanSchiller 如果您将print(commenterUid, commentText) 行留在 for 循环中,它是否会为每条评论打印这些内容?
  • @RyanSchiller 你确定 cmets 数组是空的吗?在我拥有//create a commentClass 的最后一段代码中,您应该创建一个注释类,然后是self.commentArray.insert...。然后按照 for 循环(不在里面)应该重新加载 tableView。除此之外,请确保您的 tableView 具有它的数据源和委托集。您可能需要连接一个测试按钮,您可以在运行 loadComments 函数后单击该按钮以打印出数组的内容。它不应为空。
  • @RyanSchiller 您的问题中有很多不相关的代码,我知道我的答案中的代码在我从现有项目中提取时有效。目前我们并不真正关心这张桌子。如果 dataSource 数组为空,那么您的 tableView 也将如此。您通常应该使用 self. 引用类变量,并且在创建 cmetsClass 对象时,可以将它们直接添加到该数组中。所以let aComment = CommentClass(......) 然后self.comment.append(aComment)。不用担心现在下单。我建议使用当前代码清理和更新问题。
  • @RyanSchiller ViewController 需要是 textVIews 以及 tableViews 的委托,因此它需要包含 UITableViewDelegate UITextViewDelegate。 tableView 委托是 viewController,它包含的 textView需要让 viewController 知道它们内部的变化,因此对于每个 textView,将其委托分配给 viewController,例如myTextView.delegate = self。见textViewDidChange
猜你喜欢
  • 2016-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-22
  • 1970-01-01
  • 2011-05-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多