返回

字典转表格:Swift TableView高效加载字典数据

IOS

将函数返回的字典数据加载到表格视图

在应用程序开发中,将函数返回的数据,特别是字典类型的数据展示到表格视图中是一项常见任务。当遇到问题,通常不是数据获取出了问题,而是如何正确地将数据源提供给表格视图。这篇博客会探讨如何处理这种情况,以及提供有效的解决方案。

问题分析

常见的场景是:一个函数处理一些逻辑并返回一个字典 (例如 [String: String]),你需要把这个字典的键值对,作为表格视图的每一行。问题核心是如何处理返回的字典数据并作为 UITableView 的数据源使用。通常出现只显示一行数据的情况是因为,你直接将整个字典传入到了单个cell,而numberOfRowsInSection没有反应字典中数据项数量。

解决方案

本质上,表格视图需要一个有序的数据集合(例如数组),才能正确的计算并显示单元格。 字典(Dictionary)类型是无序的。 所以当使用字典作为数据源时,要先对其进行转化和预处理,才能够被正确显示。主要处理思路是将字典转换为一个适合 UITableView 的数组,同时需要合理管理字典数据并展示。

解决方案一:使用字典键值对的数组

一种常见的处理办法是将字典转换为一个键值对数组(如 [(key: String, value: String)])。这个方法保证数据的有序性,并且容易进行展示和维护。

操作步骤:

  1. 修改返回数据的方法: getIngredientsAndMeasures方法,改为返回键值对数组,以便tableView正确读取:
 func getIngredientsAndMeasures() -> [(key: String, value: String)] {
     var dictionary: [String : String] = [:]
     let measures = getAllMeasures()
     for (index, element) in getAllIngredients().enumerated() {
         if !element.isEmpty {
             dictionary[element] = measures[index]
         }
     }
     
     // 转换字典为键值对数组
     var array = [(key: String, value: String)]()
     for (key, value) in dictionary {
         array.append((key, value))
     }
     return array
 }

  1. 修改 DetailTableViewController ,获取数组并配置 TableView:

    • 添加属性存储处理后的数组。
    class DetailTableViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
        var idMeal: String = ""
        var mealDetails = [MealDetails]()
        //新增属性存储 ingredients 和 measure数据。
        var ingredientsAndMeasures: [(key: String, value: String)] = []
      ....
    }
    
    
    • 在数据加载完成后,更新属性,同时reload表格数据。
        getApiDetailData {
            print("data loaded")
            self.view.reloadInputViews()
    
             self.ingredientsAndMeasures = self.mealDetails[0].getIngredientsAndMeasures()
             self.detailTableView.reloadData()
    
    
            self.nameLabel.text = self.mealDetails[0].name
            self.instructionsText.text = self.mealDetails[0].instructions
    
            let urlString = (self.mealDetails[0].image)
            let url = URL(string: urlString!)
            self.imageView.downloaded(from: url!)
    
        }
    
    • 修改 numberOfRowsInSectioncellForRowAt 使用 ingredientsAndMeasures
    func tableView(_ detailTableView: UITableView, numberOfRowsInSection section: Int) -> Int {
           return ingredientsAndMeasures.count
       }
    
    func tableView(_ detailTableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell(style: .subtitle, reuseIdentifier: nil)
        let item = ingredientsAndMeasures[indexPath.row]
        cell.textLabel?.text = item.key
        cell.detailTextLabel?.text = item.value
        return cell
     }
    

解决方案二:使用字典的键或者值作为数组

如果只需要展示字典的键或值,可将字典转换为键数组或值数组。这种方式在简单展示的时候很有用,不过不方便查看完整的键值对。
假设此处我们取字典的key来展示(代码与方案一相似,不再展示完整的class文件)。

  // 修改数据获取逻辑
func getIngredientsAndMeasuresKeys() -> [String] {
    var dictionary: [String : String] = [:]
        let measures = getAllMeasures()
        for (index, element) in getAllIngredients().enumerated() {
            if !element.isEmpty {
                dictionary[element] = measures[index]
            }
        }
    // 只取 key 值作为返回
        return Array(dictionary.keys)
 }
  • DetailTableViewController需要进行相应修改,与方案一类似:
    ```swift
    var ingredientsKeys: [String] = []

    getApiDetailData {
          ....
    
        self.ingredientsKeys = self.mealDetails[0].getIngredientsAndMeasuresKeys()
        self.detailTableView.reloadData()
         ....
    
       }
    

    func tableView(_ detailTableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return ingredientsKeys.count
    }
    func tableView(_ detailTableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = UITableViewCell(style: .default, reuseIdentifier: nil)
    cell.textLabel?.text = ingredientsKeys[indexPath.row]
    return cell
    }

```

代码示例与说明

以上的代码示例已经分别嵌入到每个方案的步骤中了。这里我们做一点总结:

  • getAllIngredientsgetAllMeasures 函数提取成分和计量数据。

  • getIngredientsAndMeasures 用于组合成分和计量, 并按要求转换成对应的返回格式(字典,数组,或者键值对数组)。

  • 在 TableViewController 中使用合适数据源进行配置,在数据准备完毕后刷新tableView数据。

额外的安全建议

  • 数据为空保护:在数据加载和转化阶段,添加可选值判断,避免nil值导致程序崩溃。例如,在访问mealDetails 的下标索引的时候,添加mealDetails.indices.contains(0)判断。
  • 后台数据校验:如果数据来源于服务器,在服务器返回的数据之后,需要对数据的有效性进行验证,避免后端错误返回脏数据导致APP崩溃或显示错误。
  • 使用TableView自带的dequeueReusableCell机制,以优化列表展示。
  • 进行多线程优化,减少主线程的耗时。将复杂数据处理放入异步线程,完成后更新主线程进行 UI 展示。

通过以上解决方案和最佳实践,你应可以有效地处理和显示从函数返回的字典类型数据,使其在表格视图中得到正确的呈现。