新的 Firebase 数据导致 TableView 单元格闪烁 (Firebase/iOS/Swift)

2023-12-10

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

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

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

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

由于我缺乏知识,除了经历这个循环之外,我不知道如何显示数据。我认为这个循环可能会导致闪烁,但我不知道如何让它加载数据。我尝试过各种其他方法,例如使用查询,但我从未能够让它工作。

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

另外,我就是找不到好的,recent在 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 {

    }

}

UPDATE:

我弄清楚了如何使用之前的 stackoverflow 帖子中概述的查询和委托模式:

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

我这边的代码解决了这个问题:

根据 Jay 的建议,我删除了不必要的 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
   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

以上代码经过测试,没有闪烁。显然,它需要根据您的用例进行调整,因为您有一些图像要加载等,但上述内容应该可以解决问题并且更易于维护。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

新的 Firebase 数据导致 TableView 单元格闪烁 (Firebase/iOS/Swift) 的相关文章

  • AppStore 提交:错误 ITMS-9000:“无效的捆绑结构 - 不允许二进制文件‘MyApp.app/BuildAgent’

    我陷入了以下错误 我根本不明白 错误 ITMS 9000 无效的捆绑结构 不允许使用二进制文件 MyApp app BuildAgent 您的应用程序可能只包含一个可执行文件 当我使用 Xcode 从 Archive 导出到 IPA 时 我
  • 从 UIPickerView 的选定行设置 UIButton 的标题

    详细场景是这样的 我使用循环创建 10 个按钮并设置 0 9 的标签 点击每个按钮时 我将调用 UIPickerView 在其中加载来自不同数组的数据 到这里我就得到了预期的结果 但我希望 pickerView 中选定的行应设置为相应按钮的
  • React-native-vision-camera无法访问后面的普通摄像头

    我正在尝试在 iPhone 11 Pro 上使用 普通 相机 我使用反应本机视觉相机 当我运行这段代码时 const devices useCameraDevices const deviceBack devices back consol
  • 将自定义数据包含到 iOS 故障转储中

    你好 堆栈溢出 有一个简单的问题要问您 当我的应用程序在用户的设备上崩溃时 是否可以将自定义错误数据嵌入到自动生成的 iOS 故障转储中 例如 我的 SQlite 数据库由于某种原因无法运行 例如 数据库文件已损坏 我无法从这个错误中恢复
  • 如何制作带有 SWIFT 图像的弹出窗口

    我想知道如何制作类似于此示例的弹出窗口 原始窗口充满了按钮 选择这些按钮后将拉出我想要使用的图像 我会简单地创建一个可重用的UIView组件以及作为子视图所需的一切 例如UIImageView为了你的形象 UILabel or a UIBu
  • 如何从 SDK 实现每个会话的 Google Places 自动完成功能?

    是否可以从 Android 和 iOS 应用程序的 place sdk 实现基于会话的自动完成 根据 6 月 11 日生效的新 Google 地图框架定价 对自动完成的请求可以分为基于击键 会话的请求 我找不到描述实施步骤的文档 除了这个参
  • 错误域=kAFAssistantErrorDomain 代码=209“(空)”

    我面临着一个问题SFSpeechRecognizer 启动应用程序几秒钟后 我开始收到错误消息 错误域 kAFAssistantErrorDomain 代码 209 空 和 错误 域 kAFAssistantErrorDomain 代码 2
  • 我在布局上看不到任何 FirebaseRecyclerAdapter 项目

    我试图将数据从 Firebase 数据库检索到我的布局 但我看不到任何项目FirebaseRecyclerAdapter在布局中 请帮忙 我按照一个教程展示了如何做到这一点 当我运行应用程序时 我没有看到任何项目 但我可以滚动 public
  • 无法在 Swift 中对闭包进行弱引用

    Update 我试着不弱化地写一下 好像也没有漏的情况 所以也许这个问题已经没有必要了 在 Objective C ARC 中 当你想让一个闭包能够在闭包内部使用它自己时 该块不能捕获对自身的强引用 否则它将是一个保留循环 因此您可以使闭包
  • CALayer边框奇怪问题

    我正在向 CALayer 添加边框 但有一些奇怪的行为 在我应用的边框之后出现模糊边框 参见屏幕截图 这是我的代码 void configureLabel self hidden YES self textAlignment NSTextA
  • 从按钮执行 Segue 时应用程序冻结

    我的故事板中有一个按钮 它呈现一个带有模式序列的视图控制器 每次按下此按钮时 应用程序都会冻结 没有崩溃 也没有错误消息 prepareForSegue被调用 所有应该存在的视图控制器都在代码中prepareForSegue 但它们不会出现
  • 为什么 iOS 启动屏幕很慢?

    我的 iOS 应用程序启动屏幕大约需要 3 5 秒 我有一张将在启动屏幕后加载的地图 我的用户必须等待启动屏幕加载 然后再等待 3 秒才能加载地图 有没有办法最大限度地减少启动屏幕时间 基本上这种延迟意味着you在启动过程中做了一些非常错误
  • 会话重新启动后 AVcapture 会话启动缓慢

    我有一个主视图控制器 它连接到具有 avcapturesession 的第二个视图控制器 我第一次从主视图控制器转向捕获会话控制器 大约需要 50 毫秒 使用 仪器 检查 然后我从捕获会话返回到主视图控制器 然后从主控制器返回到 avcap
  • UIViewControllerAnimatedTransitioning:旋转更改后黑屏片段

    我已经创建了一个视图控制器转换 只要我不更改设备方向 一切都正常 图 1 显示了应有的屏幕 然后我切换到下一个视图控制器 在其中更改方向 现在我回到第一个视图控制器并再次切换方向 然后我得到的结果如图 2 所示 出现黑色边框 请不要介意屏幕
  • watchOS 错误:控制器接口描述中的未知属性

    我将 WKInterfacePicker 添加到情节提要中 并将其连接到界面控制器中的 IBOutlet 运行应用程序时 它在控制台中显示一条错误消息 控制器的接口描述 watchPicker 中的未知属性 Code interface I
  • 根据一个数组对多个数组进行排序

    如何根据数组对一堆数组进行排序createdAt 例如 2015 11 02 19 19 35 0000 将它们组合成另一种类型 字典 以便在 tableView 中使用是否有益 如果有的话如何 var comment AnyObject
  • Objective-C 中发送给对象的消息可以被监听或者打印出来吗? [复制]

    这个问题在这里已经有答案了 可能的重复 Objective C 中拦截方法调用 https stackoverflow com questions 1618474 intercept method call in objective c 如
  • 如何更改 SwiftUI 列表中分隔符的颜色?

    我在 SwiftUI 中创建了一个列表 我想更改颜色或删除分隔符 因为在 UIKit 中 我们可以轻松更改 TableView 中分隔符的颜色 下面是 SwiftUI 中列表的代码和 UI 图片 State private var user
  • 没有用于警告的设置器/字段 Firebase 数据库检索数据填充列表视图

    我只是想将 Firebase 数据库中的数据填充到我的列表视图中 日志显示正在检索数据 但适配器不会将值设置为列表中单个列表项中的文本 它只说 没有二传手 场地插入值 这让我觉得我的设置器没有正确制作 但 Android Studio 自动
  • ios - 如何声明静态变量? [复制]

    这个问题在这里已经有答案了 C 中声明的静态变量如下 private const string Host http 80dfgf7c22634nbbfb82339d46 cloudapp net private const string S

随机推荐

  • 关于根据年份生成年龄变量的思考

    多年来我一直试图创建一个虚拟变量 目前 我的数据有每个观察的出生日期和程序开始日期 我已经能够创建一个以天为单位测量个人年龄的变量 但我实际上正在寻找的是一个变量 age join date 它告诉我以下内容 Individual birt
  • Haskell:列表、数组、向量、序列

    我正在学习 Haskell 并阅读了几篇有关 Haskell 列表和 插入您的语言 数组的性能差异的文章 作为一名学习者 我显然只是使用列表 甚至没有考虑性能差异 我最近开始调查并发现 Haskell 中有许多可用的数据结构库 有人可以在不
  • URL 中 Hash(#) 的使用

    我想知道除了作为 URL 中的锚点之外 哈希还有其他用途吗 我在这里读到了它获取完整的 url 包括哈希后的查询字符串 客户端的状态信息是什么 请帮忙 哈希也可用于单页面应用程序 因此您可以使用哈希作为从一个页面导航到另一个页面的方式 而不
  • C# 使用 LINQ 选择行的最大 ID

    我有一个面包屑表 我想返回最近插入的行 在 SQL 中它将是MAX 函数 但不确定如何在 LINQ 中执行等效操作 基本上我想选择具有最高的行BreadCrumbID WHERE ProjectID 49 这是我现在的查询 它将选择所有行W
  • Java 中的并行计算 [关闭]

    Closed 这个问题需要多问focused 目前不接受答案 如何在 Java 中使用并行 或者我使用普通线程 阅读Java并发教程 创建多个线程来为您完成工作
  • Java中根据天数获取日期

    简单的问题 但令人惊讶的是谷歌对此几乎没有什么了解 我有number of days从今年1月1日开始 我怎样才能将其转换为date在Java中 你可以简单地使用SimpleDateFormat转换String to Date 图案D可以用
  • 如何将 int 转换为 NSString?

    我想转换一个int to a NSString在目标 C 中 我怎样才能做到这一点 基元可以转换为对象 表达 所以shortest方法就是转变int to NSNumber并选取字符串表示形式stringValue method NSStr
  • 泛型集合“无法实例化类型 ArrayList

    根据我读到的内容 我认为这是不可能的 但我想确定一下 我有课OpDTO和其他几个 DTO extends OpDTO 然后 我想要一种方法从这些子 DTO 的列表中仅提取某些元素 并在另一个列表中返回提取的元素 public List
  • komodo edit 7.1 在 php 模式下无法识别 html5 标签

    标题已经很说明性了 在 php 模式下 komodo edit 假定 html4 并在使用像文章 时间 部分这样的 html5 标签时引发错误 这可能会很麻烦 因为它可能会覆盖 php 错误 有没有办法来解决这个问题 也许找到了解决方案 首
  • 检测网页上的合成点击

    通过 Javascript 是否可以检测合成点击 不是由人类生成而是使用 JS 或其他自动化工具生成的点击 也许我们可以做这样的事情 document onmousedown function e if typeof e pageX und
  • Cocoapods pod 稳定构建设置

    有没有办法在中添加构建设置cocoapodspod 无需直接更改 Pods 项目或其他自动生成的内容 因此在之后它仍然会存在pod install 具体来说 我需要设置DISABLE MIXPANEL AB DESIGNER 1在 Mixp
  • Yii - “白屏死机”,调试技巧

    我有一个运行 Yii 应用程序的临时服务器 现在出现 死机白屏 我看不到屏幕上输出的任何内容 甚至 查看源代码 时的源代码 在本地相同的代码运行没有任何问题 任何人都可以建议一个在 Yii 应用程序中调试 死机白屏 的好例程吗 在 yii
  • asp.net 会员提供商 Guid userID

    我需要 我认为 获取当前登录的用户 ID 以便我可以更新使用此用户 ID 作为外键的表之一 问题是数据库中的userID与此不匹配 Guid currentUser Guid Membership GetUser ProviderUserK
  • 仅安装较新的框架时应用程序是否会运行

    我似乎找不到我的问题的答案 所以我只是在这里问 假设我有一个为 Net Framework 4 62 构建的应用程序 它可以在只安装了 4 7 的服务器上运行吗 当然除了一些旧的框架 或者我需要安装每个目标框架吗 NET Framework
  • 如何使用 CSS 透视将元素定位在正确的 3D 位置

    我正在尝试找到一种方法来在以给定角度放置的照片元素之上映射元素 笔记本电脑的照片就是一个很好的例子 我想在屏幕顶部映射一个元素 视频 图像或其他 例如循环播放视频等 这个任务看起来很简单 但我发现它非常棘手 因为我找不到如何通过变换 旋转
  • 标签为类别页面 Blogger 中的标题

    我有一个网站 可以在其中显示具有所有相同标签的帖子 有没有办法在显示具有相同标签的所有帖子时将标签作为标题 例如 关于https newsotuniverse blogspot ca search label astrophysicals有
  • Swift 中每次动画迭代后的延迟

    我有一个核心动画 repeatCount被设定为Float infinity 在动画的每次迭代之后 即 每次重复之后 我想要延迟 3 秒 我怎样才能实现这个目标 谢谢 您可以使用function像下面这样做你需要做的事情 func anim
  • 从 Delphi 访问 Android 的 SharedPreferences 类

    我刚刚开始使用 Delphi XE5 进行 Android 开发 并尝试构建一个简单的应用程序 该应用程序需要能够保留一些输入的信息 配置 我已经弄清楚了 Android 类共享首选项可能是最简单的方法 但我不知道如何从 Delphi XE
  • 协程演示源码

    这是一个程序示例 其中协程确实有助于简化 该算法 恕我直言 否则很难实现 我还尝试为演示选择一个有用的任务 该实用程序将 一个二进制文件到一系列 A Z 符号 以及后面 没有任何显着的 冗余 并且它能够处理任何指定的字母表 参见 M Ini
  • 新的 Firebase 数据导致 TableView 单元格闪烁 (Firebase/iOS/Swift)

    我的主要问题是如何消除闪烁 但我也只是想知道我是否正确且最有效地处理非规范化 Firebase 数据 我的方法接近正确吗 因此 我正在努力尝试使用已非规范化的数据正确显示 firebase 数据库中的数据 我有帖子 然后是与每个帖子相关的评