如何初始加载 UITableView 然后观察 Firebase 节点以更改在 Swift 中刷新 tableview?

Posted

技术标签:

【中文标题】如何初始加载 UITableView 然后观察 Firebase 节点以更改在 Swift 中刷新 tableview?【英文标题】:How to initial load UITableView then observe Firebase node for changes to refresh tableview in Swift? 【发布时间】:2019-05-14 06:32:59 【问题描述】:

我正在加载 UITableViewUser 数据,最初使用 observeSingleEventFirebase 获取数据,据我所知,在初始读取后不会附加观察者。

我还在每个单元格中都有一个图标,当用户在线/离线时会更新。为此,我在willDisplay 单元委托方法中将观察者附加到observe 对特定User 子节点的任何更改,并在didEndDisplaying 方法中删除观察者。

这是我第一次这样做并且工作正常,但在继续之前,我想知道这是否是最初加载数据然后观察变化的行业标准方式,以便可以为每个单元格相应地更新视图。

cellForRowAt 出列和配置单元格的方法:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 

       guard let cell = tableView.dequeueReusableCell(withIdentifier: "ConversationsListCell", for: indexPath) as? ConversationsListCell else  return UITableViewCell() 

        let message = messages[indexPath.row]


        DataService.run.getUserInfo(forUserId: message.chatPartnerId()!)  (user) in
            cell.configureCell(message: message, user: user)
        
        return cell

    //end func

willDisplay 方法在特定子节点处附加一个观察者,如果该节点有任何变化,则触发 tableView.reload():

func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) 

        let message = messages[indexPath.row]

        DataService.run.observeUserNodeChages(forId: message.chatPartnerId()!)  (user) in
            self.tableView.reloadData()
        

    //end func

didEndDisplaying 方法移除willDisplay 方法附加的观察者:

func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) 

        if indexPath.row < messages.count 

            let message = messages[indexPath.row]
            DataService.run.removeObserveUserNodeChages(forId: message.chatPartnerId()!)
        

    //end func

observeUserNodeChages 监听特定 uid 子节点的任何变化

func observeUserNodeChages (forId: String, handler: @escaping (Bool) -> ())

        print("inside observeUserNodeChages forId:\(forId)")

        conversationListHandle = REF_USERS.child(forId).observe(.childChanged, with:  (snapshot) in

           handler(true)

        , withCancel: nil)

    //end func

user节点 Firebase 结构

【问题讨论】:

我们确实需要查看您用于观察 Firebase 节点的代码。还有一点不清楚为什么你使用委托,删除观察者和问题中代码的目的,因为它缺乏一点上下文。通常,您会向 Firebase 添加一个 .childChanged 观察者,它会通知您更改并将更改的节点传递给您的应用程序。从那里您将更新 tableview 数据源并在需要时重新加载受影响的单元格。您能否澄清问题,添加代码以提供上下文并包含您的 Firebase 结构,以便我们查看您使用的数据? 感谢您的回复@Jay 我的问题是关于我的实施是否是最佳方法。 uitable 由发送给包含发件人uid 的用户的messages 列表填充,我使用uid 然后使用observeSingleEvent .value 从我的cellForRowAt 中的Firebase 获取user 详细信息.所以我的逻辑是在我的willDisplay 中的users 节点中设置一个较低级别的观察者并监听任何更改而不是监听所有用户更改我只想知道该特定用户节点的更改。如果有更改,则重新加载 tableview。 我会说这不是一个好的实现,因为您的 tableView 和 UI 响应能力取决于您的互联网连接。例如,这会使滚动变得异常缓慢。您不应该对每个单元格 ping Firebase - 数据应该已经存在,因此当您的 tableView 刷新时,您不会重复访问互联网。最佳做法是从 Firebase 填充您的 tableView 数据源,然后仅在收到来自 Firebase 的事件时更新该数据源。 【参考方案1】:

我想知道这是否是行业标准方式

这不是行业标准方式,应避免使用,因为它会导致 UI 闪烁和响应缓慢。但是,在编码方面,通常没有“标准”,因为您为解决问题而编写的代码会因用例和所需结果而异。

您的 tableView 数据源最初应从 Firebase 填充,然后在发生更改时更新;这将由 Firebase 事件启动。更新数据源后,刷新 tableView。

这将使应用保持响应并让您的用户满意。

另一件事是您似乎在同一个(用户)节点中附加了多个观察者。这可能没有必要;将您的观察者附加到 /users 节点,然后您将收到添加、更改或删除事件的通知,并且受影响的任何用户都将作为快照传递给 firebase 闭包。

【讨论】:

一个问题,假设我在 Firebase 中有 10,000 名用户,他们不断地在线/离线,因此每次发生这种情况时都会更新 Firebase,我的应用程序每次也会收到那些更新的 user 节点。而且由于我只为 100 个用户加载 user 数据,因此对于我的应用程序来说,接收所有其他 9,900 个用户的更新似乎是不必要的。你建议的方法仍然是最好的方法吗?有没有办法只收听我的应用感兴趣的 100 个用户的更新? @Roggie 10,000 个用户并不是什么大问题。随着每个用户的状态发生变化,少量数据会通过快照提供给应用程序,并且 tableView 也会相应更新。如果需要,您甚至可以只更新该行的单元格,但一般来说,只需重新加载或刷新该行就足够了。如果您只加载一个用户子集,如果需要,您可以只观察该子集。我知道下意识的反应是避免监控 10,000 个用户,但现实情况是,并非所有人都会同时下线/上线,而且可能会更少。

以上是关于如何初始加载 UITableView 然后观察 Firebase 节点以更改在 Swift 中刷新 tableview?的主要内容,如果未能解决你的问题,请参考以下文章

heightForRowAtIndexPath 和 UITableView scrollToBottom 的初始加载性能不佳

将 plist 数据加载到 UITableView 时从不调用惰性初始化程序

UITableView - 从单独的类中重新加载数据

如何在 RxSwift 中观察 UITableView 点击/选择的先前值和当前值?

UITableView - 你如何重新加载全新的数据?

如何在uitableview中加载数据而不每次都重新加载