Как получить документы Cloud Firestore и отобразить данные в TableView? - PullRequest
0 голосов
/ 15 апреля 2020

У меня есть структура данных: Моя база данных Firestore

Как вы увидите, у меня есть документ "Michael 201A", а также "Michael 201B", идея которого состоит в том, чтобы получить поля из этих документов и отображать их в виде таблицы. Кроме того, я хотел бы, чтобы tableView обновлялся автоматически на основе любых новых документов, добавляемых в коллекцию «Запросы», чтобы данные tableView всегда заполнялись самыми последними добавлениями в базу данных firestore.

Функция для извлечения данных из FireStore

@IBOutlet weak var tableView: UITableView!

var db: Firestore!

var requestArray = [Request]()


override func viewDidLoad() {
    super.viewDidLoad()

    db = Firestore.firestore()
    tableView.delegate = self
    tableView.dataSource = self
    loadData()
}

    func loadData() {

    db.collection("Requests").whereField("Status", isEqualTo: true).getDocuments() {(querySnapshot, err) in
        if let err = err {
            print("An error occurred\(err)")
        } else{
            self.requestArray = querySnapshot!.documents.compactMap({Request(dictionary: $0.data())})
            print(self.requestArray)
            DispatchQueue.main.async {
                self.tableView.reloadData()
            }
            }


   }
}

Я добавил оператор печати, чтобы получить чтение значения, но он возвращает пустое.

Мои функции tableView

extension ResidentAdvisorViewController: UITableViewDelegate {

    func tableView (_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
       print("You tapped me")
   }
}

extension ResidentAdvisorViewController: UITableViewDataSource {

   func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
       // #warning Incomplete implementation, return the number of rows
    return requestArray.count
   }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

         let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)

        let request = requestArray[indexPath.row]


        cell.textLabel?.text = "\(request.Name)"
        return cell
    }
}

Структура моего запроса

protocol DocumentSerializable {
init?(dictionary:[String:Any])

}

struct Request {
var Name: String
var Dorm: String
var Room: Int
var Status: Bool
var UID: String
var TimeStamp: Date

var dictionary:[String:Any] {
return [
    "Name":Name,
    "Dorm":Dorm,
    "Room":Room,
    "Status":Status,
    "UID": UID,
    "TimeStamp": TimeStamp
    ]
}

}

extension Request : DocumentSerializable {
init?(dictionary: [String : Any]) {
    guard let name = dictionary["Name"] as? String,
    let dorm = dictionary["Dorm"] as? String,
        let room = dictionary["Room"] as? Int,
        let status =  dictionary["Status"] as? Bool,
        let uid = dictionary["UID"] as? String,
        let timestamp = dictionary["Timestamp"] as? Date
    else { return nil}

    self.init(Name: name, Dorm: dorm, Room: room, Status: status, UID: uid, TimeStamp: timestamp)

}}

В качестве примечания я проверил, чтобы мой идентификатор ячейки совпадал с "ячейкой". Кроме того, когда я изменяю текст ячейки на «Hello World», я могу отобразить его в моем tableView. Спасибо за любую помощь, спасибо.

1 Ответ

1 голос
/ 15 апреля 2020

В коде нет ничего плохого, но есть два вопроса в этом вопросе.

1) Почему значение пусто

2) Как заполнить свой источник данных изначально и затем обновите его при добавлении новых документов.

Позвольте мне сначала обратиться к 2).

Чтобы изначально загрузить данные и затем отслеживать будущие изменения, мы можем использовать .addSnapshotListener , а затем обработайте указанный c тип изменения в закрытии пожарной базы.

func observeAllRequests() {
    let requestsCollection = self.db.collection("Requests")
    let query = requestsCollection.whereField("Status", isEqualTo: true)
    query.addSnapshotListener { querySnapshot, error in
        guard let snapshot = querySnapshot else {
            print("Error fetching snapshots: \(error!)")
            return
        }

        snapshot.documentChanges.forEach { diff in
            if (diff.type == .added) {
                let name = diff.document.get("Name") as? String ?? "No Name"
                print("added: \(name)") //add to your dataSource
            }
            if (diff.type == .modified) {
                let name = diff.document.get("Name") as? String ?? "No Name"
                print("modified: \(name)") //update the request in the dataSource
            }
            if (diff.type == .removed) {
                let name = diff.document.get("Name") as? String ?? "No Name"
                print("removed: \(name)") //remove the request from the dataSource
            }
        }
        //tableView.reloadData()
    }
}

Приведенный выше код вернет все документы, соответствующие запросу. Перебирайте элементы в снимке, причем каждый из них: .added, .modified или .removed. При первом вызове функции все различия будут иметь вид .childAdded, что позволит вам первоначально заполнить источник данных.

Любые изменения документа, после этого это будет только тот документ, который был изменен с разницей, которая была добавлена ​​.added, .modified и .removed.

РЕДАКТИРОВАТЬ:

Для решения вопроса 1)

Причина, по которой массив пуст, заключается в том, как расширение структурировано - это в значительной степени все или нет. Вот как это происходит сейчас

extension Request : DocumentSerializable {
init?(dictionary: [String : Any]) {
    guard let name = dictionary["name"] as? String
    let dorm = dictionary["Dorm"] as? String,
        let room = dictionary["Room"] as? Int,
        let status =  dictionary["Status"] as? Bool,
        let uid = dictionary["UID"] as? String,
        let timestamp = dictionary["Timestamp"] as? String
    else { return nil}

    self.init(Name: name)
} }

Если поле не найдено, то все происходит сбой и возвращает ноль, а compactMap игнорирует ноль, так что в итоге вы получите пустой массив. Ваша структура не содержит метки времени, поэтому она не работает.

Я бы предложил что-то для защиты вашего кода, но с учетом пропущенных полей. Оператор с нулевым слиянием будет хорошо работать здесь

extension Request : DocumentSerializable {
   init?(dictionary: [String : Any]) {
      let name = dictionary["name"] as? String ?? "No Name"
      let room = dictionary["room") as? String ?? "No Room"
      etc
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...