使用 SnapShotListener 从 FirebaseFirestore 读取数据后如何刷新我的 UITableView?

How do refresh my UITableView after reading data from FirebaseFirestore with a SnapShotListener?

更新在底部。

我遵循了 this Apple iOS Dev Tutorial 的 UI 套件部分,直至并包括保存新提醒部分。教程在每个部分的开头提供了完整的代码供下载。

但是,我想让 FirebaseFirestore 参与进来。我还有其他一些 Firestore 项目可以运行,但我一直认为我做的事情不太正确,所以我一直在寻找更好的例子来学习。

这就是我找到 Peter Friese 的 3 部分 YT 系列“Build a To-Do list with Swift UI and Firebase”的方式。虽然我没有使用 SwiftUI,但我认为 Firestore 代码应该只需进行一些更改即可工作,因为他创建了一个存储库,其唯一功能是在应用程序和 Firestore 之间进行交互。不涉及 UI。所以,按照他的例子,我添加了一个 ReminderRepository.

它不起作用,但我所以接近。 UITableView 看起来是空的,但我知道正在加载记录。

在调试器中单步执行,我看到第一次调用 numberOfRowsInSection 时,数据还没有从 Firestore 加载,所以它是 returns 0。但是,最终代码 确实 加载数据。我可以在映射时看到每个 Reminder,最后,所有文档都加载到 reminderRepository.reminders 属性.

但我不知道如何获得 loadData() 以便稍后重新加载 table。

ReminderRepository.swift

    class ReminderRepository {
      let remindersCollection = Firestore.firestore()
          .collection("reminders").order(by: "date")

      var reminders = [Reminder]()

      init() {
        loadData()
      }

      func loadData() {
        print ("loadData")
        remindersCollection.addSnapshotListener { (querySnapshot, error) in
            if let querySnapshot = querySnapshot {
                self.reminders = querySnapshot.documents.compactMap { document in
                    do {
                        let reminder = try document.data(as: Reminder.self)
                        print ("loadData: ", reminder?.title ?? "Unknown")
                        return reminder
                    } catch {
                        print (error)
                    }
                    return nil
                }
            }
            print ("loadData: ", self.reminders.count)
        }
    }
}

与 Apple 代码的唯一区别是在 ListDataSource.swift 文件中,我添加了:

   var remindersRepository: ReminderRepository

   override init() {
     remindersRepository = ReminderRepository()
   }

并且该文件中的所有 reminders 引用都已更改为

remindersRepository.reminders.

我需要为 init() 提供回调吗?如何?我对这件事还是有点怀疑。

更新:不是完整的信用解决方案,但越来越接近。

我在 ReminderListViewController.viewDidLoad() 以及引用的函数中添加了两行:

    refreshControl = UIRefreshControl()
    refreshControl?.addTarget(self, action: #selector(refreshTournaments(_:)), for: .valueChanged)

@objc
private func refreshTournaments(_ sender: Any) {
    tableView.reloadData()
    refreshControl?.endRefreshing()
}

现在,当我盯着最初的空白table,我从顶部下拉,它会刷新。现在,如何让它自动执行此操作?

请尝试将 var reminders = [Reminder]() 更改为

var reminders : [Reminder] = []{
   didSet {
      self.tableview.reloadData()
   }
}

首先创建一些 ReminderRepositoryDelegate 协议,它将处理您的控制器部分(在您的情况下 ReminderListDataSource )和您的模型部分(在您的情况下 ReminderRepository )之间的通信。然后设置reminder后通过委派controller加载数据。以下是一些步骤:

  1. 正在创建委托协议。

     protocol ReminderRepositoryDelegate: AnyObject {
     func reloadYourData()
    

    }

  2. 符合ReminderListDataSource 委托协议:

     class ReminderListDataSource: UITableViewDataSource, ReminderRepositoryDelegate {
     func reloadYourData() {
         self.tableView.reloadData()
     }
    

    }

  3. 将委托弱变量添加到 ReminderRepository 中,它将弱化您的控制器。

       class ReminderRepository {
             let remindersCollection = Firestore.firestore()
                 .collection("reminders").order(by: "date")
    
             var reminders = [Reminder]()
             weak var delegate: ReminderRepositoryDelegate?
             init() {
                 loadData()
             }
    

    }

  4. 在创建ReminderRepository

    时将ReminderListDataSource 设置为委托
     override init() {
     remindersRepository = ReminderRepository()
     remindersRepository.delegate = self
    

    }

  5. 设置提醒后加载数据

     func loadData() {
     print ("loadData")
     remindersCollection.addSnapshotListener { (querySnapshot, error) in
         if let querySnapshot = querySnapshot {
             self.reminders = querySnapshot.documents.compactMap { document in
                 do {
                     let reminder = try document.data(as: Reminder.self)
                     print ("loadData: ", reminder?.title ?? "Unknown")
                     delegate?.reloadYourData()
                     return reminder
                 } catch {
                     print (error)
                 }
                 return nil
             }
         }
         print ("loadData: ", self.reminders.count)
     }
    

    }