字典转表格:Swift TableView高效加载字典数据
2025-01-23 22:46:27
将函数返回的字典数据加载到表格视图
在应用程序开发中,将函数返回的数据,特别是字典类型的数据展示到表格视图中是一项常见任务。当遇到问题,通常不是数据获取出了问题,而是如何正确地将数据源提供给表格视图。这篇博客会探讨如何处理这种情况,以及提供有效的解决方案。
问题分析
常见的场景是:一个函数处理一些逻辑并返回一个字典 (例如 [String: String]
),你需要把这个字典的键值对,作为表格视图的每一行。问题核心是如何处理返回的字典数据并作为 UITableView
的数据源使用。通常出现只显示一行数据的情况是因为,你直接将整个字典传入到了单个cell,而numberOfRowsInSection
没有反应字典中数据项数量。
解决方案
本质上,表格视图需要一个有序的数据集合(例如数组),才能正确的计算并显示单元格。 字典(Dictionary)类型是无序的。 所以当使用字典作为数据源时,要先对其进行转化和预处理,才能够被正确显示。主要处理思路是将字典转换为一个适合 UITableView
的数组,同时需要合理管理字典数据并展示。
解决方案一:使用字典键值对的数组
一种常见的处理办法是将字典转换为一个键值对数组(如 [(key: String, value: String)]
)。这个方法保证数据的有序性,并且容易进行展示和维护。
操作步骤:
- 修改返回数据的方法:
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
}
-
修改
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!) }
- 修改
numberOfRowsInSection
与cellForRowAt
使用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
}
```
代码示例与说明
以上的代码示例已经分别嵌入到每个方案的步骤中了。这里我们做一点总结:
-
getAllIngredients
和getAllMeasures
函数提取成分和计量数据。 -
getIngredientsAndMeasures
用于组合成分和计量, 并按要求转换成对应的返回格式(字典,数组,或者键值对数组)。 -
在 TableViewController 中使用合适数据源进行配置,在数据准备完毕后刷新tableView数据。
额外的安全建议
- 数据为空保护:在数据加载和转化阶段,添加可选值判断,避免nil值导致程序崩溃。例如,在访问
mealDetails
的下标索引的时候,添加mealDetails.indices.contains(0)
判断。 - 后台数据校验:如果数据来源于服务器,在服务器返回的数据之后,需要对数据的有效性进行验证,避免后端错误返回脏数据导致APP崩溃或显示错误。
- 使用TableView自带的dequeueReusableCell机制,以优化列表展示。
- 进行多线程优化,减少主线程的耗时。将复杂数据处理放入异步线程,完成后更新主线程进行 UI 展示。
通过以上解决方案和最佳实践,你应可以有效地处理和显示从函数返回的字典类型数据,使其在表格视图中得到正确的呈现。