新的Firebase数据导致TableView单元格闪烁(Firebase/iOS/Swift) [英] New Firebase Data Causes Flicker of TableView Cells (Firebase/iOS/Swift)

查看:38
本文介绍了新的Firebase数据导致TableView单元格闪烁(Firebase/iOS/Swift)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

My main question is how to get rid of the flicker, but I also just want to know if I am working with denormalized Firebase data correctly, and most efficiently. Is my approach anywhere near being correct?

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

So I am struggling with trying to properly display the data from a firebase database with data that's been denormalized. I have posts, and then comments associated with each post. Every time somebody opens up the comments section of a post, by segueing from a viewcontroller to a new viewcontroller, it grabs the unique key for the post (postKey), and then scans the group of comments associated with the postKey contained in the postCommentGroup. The group of comments, which are children of each postKey in the postCommentGroup are just the commentKey as key and "true" as the value, which indicates which comments are associated with which posts. The comments are in an entirely different branch as that is what I think the Firebase documentation suggests one should do.

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

I essentially have 3 layers of nested observers.

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

For the sake of clarity I'm recycling the cells with dequeuereusablecells in a tableview, and I also have a rudimentary lazy load/image caching mechanism that might be interfering with things too, but I have the same mechanism on other less complicated tableviews so I don't think that's the problem.

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

Due to my lack of knowledge I don't know how else to display the data other than going through this cycle. I think this cycle, may be causing the flicker, but I don't know how else to make it load the data. I have tried various other ways of doing it, such as using a query, but I've never been able to get it to work.

作为旁注,我试图加快如何查询数据的速度(我认为这可能会对我有所帮助),但是Swift的语法进行了更新,Firebase进行了更新,前面的示例有点难以理解.

As a side note, I've tried to get up to speed on how to query data (which I assume might help me), but there's been an update to the syntax of Swift, and also an update to Firebase, making the previous examples a little difficult to follow.

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

Also, I just can't find good, recent examples of properly using denormalized data in a somewhat complex way in any of the Firebase documentation, either on the Firebase site or on Github. Does anyone know of good reference material to look at with regard to working with denormalized data using Swift 3.0 and Firebase (newest version - not the legacy version), whether it's a project on GitHub, or a blog, or just a collection of the most useful posts on stackoverflow?

这是firebase数据结构:

Here is the firebase data structure:

   
"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帖子中概述的委托模式:

I figured out how to use queries and a delegate pattern outlined in a previous stackoverflow post:

从闭包中获取数据从Firebase检索数据

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

But I don't know if I am using the delegate pattern correctly.

使用查询已简化了代码,但仍在闪烁.也许我没有正确使用委托模式?

The code has been simplified by using the query, but it is still flickering. Maybe I am not using the delegate pattern correctly?

    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:

Upon Jay's suggestion I eliminated the unnecessary postCommentGroup and just queried the UID of the post the comment belongs to under the comment:

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

推荐答案

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

Your approach may need to be adjusted by simplifying. I wanted to provide all of the nuts and bolts so it's a bit lengthy and could in itself be simplified.

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

While denormalizing is normal, it's not a requirement and in some cases can add additional complexity. The 'layer' in your structure postCommentGroup, appears to be unneeded.

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

It looks like you have a view controller containing posts, and a second view controller that displays the comments when the user taps a post on the first controller.

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

You really only need a posts node and a comments node

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"

和引用该帖子的评论节点

and a comments node that references the post

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

然后,当用户点击帖子时,加载并显示评论.

then, when a user taps a post, load and display the comments.

    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

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

The above code is tested and has no flicker. Obviously it will need to be tweaked for your use case as you have some images to load etc but the above should resolve issues and be more maintainable.

这篇关于新的Firebase数据导致TableView单元格闪烁(Firebase/iOS/Swift)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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