我的主要问题是如何消除闪烁,但是我也只想知道我是否正确,最有效地使用了非规范化的Firebase数据。我的方法接近正确吗?

因此,我正努力尝试使用已规范化的数据正确显示Firebase数据库中的数据。我有帖子,然后有与每个帖子相关的评论。每次有人打开某个帖子的注释部分时,通过从一个视图控制器中筛选到一个新的视图控制器,它将获取该帖子的唯一键(postKey),然后扫描与postCommentGroup中包含的postKey关联的注释组。注释组是postCommentGroup中每个postKey的子级,只是commentKey作为键,“true”作为值,指示哪些注释与哪些帖子相关。注释位于一个完全不同的分支中,因为我认为Firebase文档建议这样做。

我基本上有3层嵌套的观察者。

为了清楚起见,我在表视图中使用dequeuereusablecells回收单元,并且我也有一个可能会干扰事物的基本懒惰加载/图像缓存机制,但是在其他较不复杂的表视图中我具有相同的机制,因此不要以为那是问题。

由于缺乏知识,除了经历此循环外,我不知道该如何显示数据。我认为这个周期可能导致闪烁,但是我不知道如何使它加载数据。我尝试了多种其他方式来执行此操作,例如使用查询,但是我从未能够使其正常工作。

附带说明一下,我尝试加快了如何查询数据的速度(我认为这可能会对我有所帮助),但是对Swift的语法进行了更新,同时对Firebase进行了更新,制作了前面的示例有点难以理解。

另外,在Firebase网站或Github上的任何Firebase文档中,我都找不到很好的最近的示例,它们以某种复杂的方式正确地使用了非规范化数据。是否有人知道使用Swift 3.0和Firebase(最新版本-不是旧版本)使用非规范化数据的好参考资料,无论它是GitHub上的项目还是博客,还是仅仅是大多数项目的集合关于stackoverflow有用的帖子?

这是firebase数据结构:


"comments" : {
        "-KaEl8IRyIxRbYlGqyXC" : {
          "description" : "1",
          "likes" : 1,
          "postID" : "-KaEfosaXYQzvPX5WggB",
          "profileImageUrl" : "https://firebasestorage.googleapis.com",
          "timePosted" : 1484175742269,
          "userID" : "9yhij9cBhJTmRTexsRfKRrnmDRQ2",
          "username" : "HouseOfPaine"
        }
      },

      "postCommentGroup" : {
        "-KaEfosaXYQzvPX5WggB" : {
          "-KaEl8IRyIxRbYlGqyXC" : true,
          "-KaEl9HiPCmInE0aJH_f" : true,
          "-KaF817rRpAd2zSCeQ-M" : true
        },
        "-KaF9ZxAekTEBtFgdB_5" : {
          "-KaFEcXsSJyJwvlW1w2u" : true

        },
        "-KaJyENJFkYxCffctymL" : {
          "-KaQYa0d08D7ZBirz5B4" : true
        }
      },
      "posts" : {
        "-KaEfosaXYQzvPX5WggB" : {
          "caption" : "Test",
          "comments" : 11,
          "imageUrl" : "https://firebasestorage.googleapis.com/",
          "likes" : 0,
          "profileImageUrl" : "https://firebasestorage.googleapis.com/",
          "timePosted" : 1484174347995,
          "title" : "test",
          "user" : "17lIDKNx6LgzQmaeQ2ING582zi43",
          "username" : "Freedom"
        }
      },


这是我的代码:
func commentGroupObserver() {

    DataService.ds.REF_POST_COMMENT_GROUP.observeSingleEvent(of: .value, with: { (snapshot) in

        if snapshot.value != nil {

            if let snapshots = snapshot.children.allObjects as? [FIRDataSnapshot] , snapshots.count > 0 {

                self.comments = []

                for snap in snapshots {

                    if let tempVarPostKeyForCommentGroup = snap.key as String? {

                        if tempVarPostKeyForCommentGroup == self.post.postKey {

                            self.postKeyForCommentGroup = tempVarPostKeyForCommentGroup

                            self.commentObservers()
                        } else {

                        }
                    } else {

                    }
                }

            }

        } else {
            print("error")
        }

    })


}


func commentObservers() {

    if postKeyForCommentGroup != nil {

        constantHandle = DataService.ds.REF_POST_COMMENT_GROUP.child(postKeyForCommentGroup).observe(.value, with: { (snapshot) in

            if snapshot.value != nil {

                if let snapshots = snapshot.children.allObjects as? [FIRDataSnapshot], snapshots.count > 0

                {

                    self.comments = []

                    for snap in snapshots {

                        if let theCommentIDForEachComment = snap.key as String? {
                             DataService.ds.REF_COMMENTS.child(theCommentIDForEachComment).queryOrdered(byChild: "timePosted").observeSingleEvent(of: .value, with: { (snapshots) in

                                if let commentDict = snapshots.value as? Dictionary<String, AnyObject> {

                                    let key = snapshots.key
                                    let comment = Comment(commentKey: key, dictionary: commentDict)
                                    self.comments.insert(comment, at: 0)
                                }
                                self.tableView.reloadData()
                            })
                        }
                    }
                }

            } else {

            }
        })

    } else {

    }

}

更新:

我在上一个stackoverflow帖子中指出了如何使用查询和委托模式:

getting data out of a closure that retrieves data from firebase

但是我不知道我是否正确使用了委托模式。

通过使用查询已简化了代码,但仍然闪烁。也许我没有正确使用委托模式?
    func commentGroupObserver() {
    DataService.ds.REF_POST_COMMENT_GROUP.queryOrderedByKey().queryStarting(atValue: post.postKey).queryEnding(atValue: post.postKey).observeSingleEvent(of: .value, with: { (snapshot) in
        self.postKeyForCommentGroup = self.post.postKey
        self.commentObservers()
    })

}

func commentObservers() {
    if postKeyForCommentGroup != nil {
        constantHandle = DataService.ds.REF_POST_COMMENT_GROUP.child(postKeyForCommentGroup).observe(.value, with: { (snapshot) in
            if snapshot.value != nil {
                if let snapshots = snapshot.children.allObjects as? [FIRDataSnapshot]
                {
                    self.comments = []
                    for snap in snapshots {
                        if let theCommentIDForEachComment = snap.key as String? {
                            DataService.ds.REF_COMMENTS.child(theCommentIDForEachComment).queryOrdered(byChild: "timePosted").observe(.value, with: { (snapshots) in

                                if let commentDict = snapshots.value as? Dictionary<String, AnyObject> {

                                    let key = snapshots.key
                                    let comment = Comment(commentKey: key, dictionary: commentDict)
                                    self.comments.insert(comment, at: 0)

                                }

                                self.didFetchData(comments: self.comments)

                            })



                        }

                    }

                }

            } else {

            }
        })

    } else {

    }

}

func didFetchData(comments data:[Comment]){
    self.tableView.reloadData()
}

}

和协议
 protocol MyDelegate{
func didFetchData(comments:[Comment]) }

我端解决该问题的代码:

在杰伊的建议下,我消除了不必要的postCommentGroup,只是在评论下查询了评论所属的帖子的UID:
    func commentObservers() {

    let queryRef = DataService.ds.REF_COMMENTS.queryOrdered(byChild: "postID").queryEqual(toValue: self.post.postKey)

    queryRef.observe(.value, with: { snapshot in

        if let snapshots = snapshot.children.allObjects as? [FIRDataSnapshot] {

            for snap in snapshots {

                if let commentDict = snap.value as? Dictionary<String, AnyObject> {
                    let key = snap.key
                    let comment = Comment(commentKey: key, dictionary: commentDict)
                    self.comments.insert(comment, at: 0)
                }
            }
        }

        self.tableView.reloadData()
    })
}

最佳答案

您的方法可能需要通过简化进行调整。我想提供所有的螺母和螺栓,所以它有点冗长,并且可以简化。

虽然非正规化是正常的,但这不是必需的,并且在某些情况下会增加额外的复杂性。您的结构postCommentGroup中的“层”似乎是不需要的。

看起来您有一个包含帖子的视图控制器,以及一个第二个视图控制器,当用户在第一个控制器上点击帖子时,该视图控制器显示评论。

您实际上只需要一个posts节点和一个comment节点

posts
   post_id_0
     title: "my post title"
     caption: "some caption"
     uid: "uid_0"
   post_id_1
     title: "another post title
     caption: "another caption
     uid: "uid_0"

和引用该帖子的评论节点
comments
   comment_0
     post_id: "post_id_0"
     uid: "uid_1"
     likes: "10"
   comment_1
     post_id: "post_id_0"
     uid: "uid_1"
     likes: "7"
   comment_2
     post_id: "post_id_1"
     uid: "uid_1"
     likes: "2"

设置:
class CommentClass {
    var commentKey = ""
    var comment = ""
    var likes = ""
}

var postsArray = [ [String: [String:AnyObject] ] ]()
var commentsArray = [CommentClass]()

加载所有帖子的代码:
    let postsRef = ref.child("posts")

    postsRef.observeSingleEvent(of: .value, with: { snapshot in

        for snap in snapshot.children {
            let postSnap = snap as! FIRDataSnapshot
            let postKey = postSnap.key //the key of each post
            let postDict = postSnap.value as! [String:AnyObject] //post child data

            let d = [postKey: postDict]
            self.postsArray.append(d)
        }
        //postsTableView.reloadData
        print(self.postsArray) //just to show they are loaded
    })

然后,当用户点击帖子时,加载并显示评论。
    self.commentsArray = [] //start with a fresh array since we tapped a post
    //placeholder, this will be the post id of the tapped post
    let postKey = "post_id_0"
    let commentsRef = ref.child("comments")
    let queryRef = commentsRef.queryOrdered(byChild: "post_id")
                              .queryEqual(toValue: postKey)

    //get all of the comments tied to this post
    queryRef.observeSingleEvent(of: .value, with: { snapshot in

        for snap in snapshot.children {
            let commentSnap = snap as! FIRDataSnapshot
            let commentKey = commentSnap.key //the key of each comment
            //the child data in each comment
            let commentDict = commentSnap.value as! [String:AnyObject]
            let comment = commentDict["comment"] as! String
            let likes = commentDict["likes"] as! String
            let c = CommentClass()
            c.commentKey = commentKey
            c.comment = comment
            c.likes = likes

            self.commentsArray.append(c)
        }

        //commentsTableView.reload data

        //just some code to show the posts are loaded
        print("post:  \(postKey)")
        for aComment in self.commentsArray {
            let comment = aComment.comment
            print("  comment: \(comment)")
        }
    })

和结果输出
post:  post_id_0
  comment: I like post_id_0
  comment: post_id_0 is the best evah

上面的代码已经过测试,没有闪烁。显然,由于要加载一些图像等,因此需要针对您的用例进行调整,但是以上内容可以解决问题并且更易于维护。

07-26 09:37
查看更多