Ios 如何从字典中检索firestore数据并填充Tableview行/节?

Ios 如何从字典中检索firestore数据并填充Tableview行/节?,ios,firebase,asynchronous,google-cloud-firestore,tableview,Ios,Firebase,Asynchronous,Google Cloud Firestore,Tableview,我正在尝试使用Firestore数据填充tableview的部分和行,这些数据是我解析并存储在字典中的,看起来像这样 dataDict = ["Monday": ["Chest", "Arms"], "Wednsday": ["Legs", "Arms"], "Tuesday": ["Back"]] 坦率地说,我甚至不确定我是否应该像以前那样将数据存储在字典中。这样做是不对的吗?此外,由于数据是异步提取的,因此只有在字典完全加载网络数据后,我才能填充节和行?我使用的是一个完成处理程序,但当我试

我正在尝试使用Firestore数据填充tableview的部分和行,这些数据是我解析并存储在字典中的,看起来像这样

dataDict = ["Monday": ["Chest", "Arms"], "Wednsday": ["Legs", "Arms"], "Tuesday": ["Back"]]
坦率地说,我甚至不确定我是否应该像以前那样将数据存储在字典中。这样做是不对的吗?此外,由于数据是异步提取的,因此只有在字典完全加载网络数据后,我才能填充节和行?我使用的是一个完成处理程序,但当我试图打印
dataDict
的结果时,它会连续打印出三个数组,如下所示

["Monday": ["Chest", "Arms"]]
["Tuesday": ["Back"], "Monday": ["Chest", "Arms"]]
["Tuesday": ["Back"], "Monday": ["Chest", "Arms"], "Wednsday": ["Legs", "Arms"]]
而我期望它在完成后返回数组的单个打印。我做错了什么


我认为这只是你计划的流程。每次循环遍历集合时,都会将它得到的内容添加到字典中。因此,在第一次通过时,它将打印字典有1项。第二步,它向字典中添加另一项,然后打印字典,现在字典中有2项,因此打印2项。我不认为您看到了意外的行为,这只是您将日志语句与循环方式排序的方式


换句话说,它这样打印是有道理的。

我同意@ewizard的答案。问题出在程序的流程中。您遍历文档,并在每次迭代中获取集合中的文档。您还可以多次重新加载tableView并调用完成闭包,这是您不想做的

要改进程序的流程,请尝试使用DispatchGroup获取数据,然后在获取所有数据后将其一次放在一起。请参见下面的示例以了解基本概念。我的示例是一个非常简化的代码版本,我想向您展示应该进行的重要更改

func loadData(completion: @escaping (Bool) -> ()) {
    self.colRef.getDocuments { (snapshot, err) in
        // Handle error

        let group = DispatchGroup()
        var fetchedData = [Any]()

        // Iterate through the documents
        for dayDocument in snapshot!.documents {
            // Enter group
            group.enter()
            // Fetch data
            Firestore.firestore().collection("/users/\(self.userIdRef)/Days/\(dayDocument.documentID)/Workouts/").getDocuments { (snapshot, err) in
                // Add your data to fetched data here
                fetchedData.append(snapshot)
                // Leave group
                group.leave()
            }
        }

        // Waits for until all data fetches are finished
        group.notify(queue: .main) {
            // Here you can manipulate fetched data and prepare the data source for your table view
            print(fetchedData)

            // Reload table view and call completion only once
            self.tableView.reloadData()
            completion(true)
        }
    }
}
我还同意其他意见,即您应该重新考虑tableView的数据模型。更合适的结构是2d数组(数组数组数组-第一个数组转换为表视图节,内部数组对象转换为节项)。 下面是一个例子:

// Table view data source
[
    // Section 0
    [day0, day1],
    // Section 1
    [day2, day3],
    // Section 2
    [day4, day5],
]
用法示例:

extension ViewController: UITableViewDataSource {

    func numberOfSections(in tableView: UITableView) -> Int {
        return sections.count
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return sections[section].count
    }

}

您是否尝试将
DispatchQueue.main.async{
放在
if self.dataDict[dayDocument.data()[“dow”]的上方作为?字符串???“”==nil{
?仍在处理代码,但可能包括在异步调用中存储数据,以及
重新加载数据
调用。这些行:
picker.delegate=self-picker.dataSource=self
不引用任何内容,您需要将tableview委托设置为具有
dataSource
如何使用e> pickeronly
picker
不是你的tableview吗?如果是,它的声明在哪里?我也不认为你应该为这样的tableview将数据存储在字典中,拥有一个数组更有意义。它更容易概念化,当tableview形成时,它会在数组中循环并占用每个插槽数组,并将其放置在一行中。您可以在数组中存储对象。就像这里的答案:我知道您在代码中看不到它,但我实际上使用的是UITableViewController,因此我不需要设置委托或数据源,它们由父级隐式设置。完全正确。并且每个文档都会调用一次完成(在这种情况下是三次),这通常不是预期的行为。这一切都在地板上
extension ViewController: UITableViewDataSource {

    func numberOfSections(in tableView: UITableView) -> Int {
        return sections.count
    }

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return sections[section].count
    }

}