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