高效刷新 TableView?

Posted

技术标签:

【中文标题】高效刷新 TableView?【英文标题】:Efficiently refreshing TableView? 【发布时间】:2017-02-24 04:54:42 【问题描述】:

我正在从我的 NoSQL Firebase 数据库中读取数据,将这些数据解析为单个组件,然后将它们显示在我的 tableView 中。我添加了表格刷新功能,因此当添加新数据时,用户可以刷新并将其添加到表格中。

调用刷新表的函数与填充初始表的函数相同,因此从某种意义上说,刷新只是重新启动视图。采取的步骤是:

    清空包含已解析数据元素的数组和字典 从数据库中获取数据 解析该数据 重新加载表格

这是完整的功能:

func readEventsFromDb() 
    // 1. Empty out data structures
    eventsForDate.removeAll()
    allDates.removeAll()

    // 2. Fetch data
    let dbRef = FIRDatabase.database().reference().child("pets").child(currentPet).child("events")
    dbRef.observeSingleEvent(of: .value, with:  snapshot in
        if let snapshots = snapshot.children.allObjects as? [FIRDataSnapshot] 
    // 3. Parse data elements
            for child in snapshots
                if let data = child.value as? [String: Any] 
                    if let c = data["comment"] as? String, let p = data["user"] as? String, let t = data["type"] as? Int, let d = data["date"] as? UInt64 
                        let event = PetEvent(comment: c, person: p, type: t, time: self.timeFromEpoch(time: Double(d)))
                        let eventDate = self.dateFromEpoch(time: Double(d))
                        if (self.eventsForDate[eventDate] != nil) 
                            self.eventsForDate[eventDate]!.append(event)
                         else 
                            self.eventsForDate[eventDate] = [event]
                        
                    
                
            
     // 4. Refresh table
            self.allDates = Array(self.eventsForDate.keys)
            self.feedTable.reloadData()
            self.refreshControl.endRefreshing()
        

    )

刷新表几乎只是重新启动视图对我来说没有多大意义,因为这是视图中唯一的东西。这是表格刷新通常的工作方式还是有更有效的方法来做这样的事情?

【问题讨论】:

您特别关注流程的哪一部分? reloadData 不会重新启动视图 - 它会回收现有的 UITableViewCell 对象(假设您的表数据源写入正确)。 我主要关心 removeAll(),也许有办法不清空数据结构。再次从数据库中读取每个事件可能并不聪明,也许有一种方法可以获取新事件。最后,我担心重新加载表格,但从你所说的情况来看,这并没有我想象的那么重要。 【参考方案1】:

使用ref.observe而不是ref.observeSingleEvent来持续更新表格视图。

ref.observe(.childAdded ...) //insert row
ref.observe(.childRemoved ...) //remove row
ref.observe(.childChanged ...) //update row

【讨论】:

确实是解决方案:Firebase 以有效更新视图所需的精确粒度触发 .child... 事件。 @FrankvanPuffelen 你好!抱歉,这不是主题,只是想让您知道您是 *** 上我最喜欢的人。感谢您一直在帮助人们,包括像我这样有前途的 CS 学生。 嘿,彼得,您是否建议在使用 .insertRowsAtIndexPaths 填充的初始表上执行此操作,或者只是为了刷新? @MarksCode 我将.observeSingleEvent(of: .value, ... tableView.reloadData()..) 用于初始表视图数据。并使用childAddedchildRemovedchildChanged 来更新tableView。 (部分数据来自.value. childAdded ,需要追加表数据选择性) @MarksCode 使用snapshot.key 作为字典键,if self.dict[snapshot.key] == nil self.dict[snapshot.key] = true // append item // insert row 【参考方案2】:

我不知道您为什么要做这么多手动工作来让用户刷新这些数据 - Firebase 的最大价值之一是您可以自动执行此操作。这可以工作,但绝对不是“大多数其他应用程序”如何做到这一点。

我强烈建议您查看 FirebaseUI 项目: https://github.com/firebase/FirebaseUI-ios

这包括 UITableView 和 UICollectionView 显示的数据源,它们处理您正在执行的 90% 的工作,但也支持增量(和动画,如其他 iOS 应用程序)行显示。例如,如果删除了一行,用户会看到该删除带有漂亮的动画,同时保持其在表格中的滚动位置。 (您概述的解决方案将失去这个位置,这不是很用户友好。)

项目中包含一个简单的示例应用程序,它使用该模块显示一个简单的实时表格: https://github.com/firebase/FirebaseUI-iOS/tree/master/FirebaseDatabaseUITests

【讨论】:

很好的答案。 FirebaseUI-iOS 实现了.child... 侦听器以有效地更新UITableViewUICollectionView。使用这些预先构建的控制器可以节省大量时间,尽管它们对于更高级的用例可能过于有限。 值得一提的是,对于高级用例,FirebaseUI(在所有平台上)包含一个通用集合类,例如 iOS 中的 FUIArray。这将为您处理所有侦听器并更新事件/委托模式,但没有任何面向显示的代码,例如将其绑定到 UITableView。例如,在需要执行滑动寻呼机/选项卡视图等操作的应用程序中,我非常幸运地使用了它。 乍得听起来很酷。你在某处有这种滑动寻呼机的代码吗?我们会定期收到有关如何执行此操作的请求。 不幸的是,我们无法将代码本身作为模块开源(只是时间限制,没有任何其他反对意见),但我们使用了github.com/guilhermearaujo/GUITabPagerViewController,这是一个非常简单的层,可以简化 UIPageViewController 的实现.我们只是使用 FUIArray 并将其委托回调连接到适当的 GUITabPagerViewController 方法。如果可以的话,我会尝试编写一个 Gist。我怀疑它是否超过 200 行代码...

以上是关于高效刷新 TableView?的主要内容,如果未能解决你的问题,请参考以下文章

tableView 局部刷新

ios 设置tableview header不刷新

tableview刷新跳动问题

像刷新一样重新加载tableview视图

TableView 的拉取刷新问题

iOS 怎么避免tableview刷新数据错乱