Swift 4中如何根据JSON数据为TableView创建正确分组?
解决TableView分组重复显示的问题
嘿,我来帮你搞定这个分组显示的bug!你现在的核心问题是没有把数据按照name的首字符进行分组存储,而且TableView的数据源方法完全没对应分组后的结构,所以才会每个分组都重复显示所有条目。咱们一步步调整:
1. 调整数据存储结构
首先把原来的figures数组和手动设置的figSectionTitles换成适合分组的结构:
struct FigureStats: Decodable { let name: String let number: String let year: String? } // 用字典存储分组数据:键是分组标题,值是该组的所有条目 var groupedFigures = [String: [FigureStats]]() // 存储排序后的分组标题(比如#、A、B、C...) var sortedSectionTitles = [String]()
2. 下载JSON后自动分组数据
修改downloadJSON方法,在解析完JSON后,自动把每个条目按name的首字符分到对应的组里,同时处理数字/特殊字符归到#组的情况:
func downloadJSON(completed: @escaping () -> ()) { guard let url = URL(string: "https://xxxx") else { print("无效的URL") return } URLSession.shared.dataTask(with: url) { (data, response, error) in if let error = error { print("请求出错:\(error.localizedDescription)") return } guard let data = data else { print("未获取到数据") return } do { // 先解析所有数据 let allFigures = try JSONDecoder().decode([FigureStats].self, from: data) var tempGroups = [String: [FigureStats]]() // 遍历每个条目,分配到对应分组 for figure in allFigures { // 处理name为空的极端情况 guard let firstChar = figure.name.first else { tempGroups["#", default: []].append(figure) continue } let firstCharStr = String(firstChar).uppercased() // 判断首字符是字母还是数字/特殊字符 if firstCharStr.rangeOfCharacter(from: .letters) != nil { // 字母归到对应大写字母的组 tempGroups[firstCharStr, default: []].append(figure) } else { // 数字/特殊字符归到#组 tempGroups["#", default: []].append(figure) } } // 保存分组数据,并对标题排序(#放最前面,字母按A-Z排列) self.groupedFigures = tempGroups self.sortedSectionTitles = tempGroups.keys.sorted { if $0 == "#" { return true } if $1 == "#" { return false } return $0 < $1 } // 回到主线程刷新UI DispatchQueue.main.async { completed() } } catch { print("JSON解析错误:\(error.localizedDescription)") } }.resume() }
3. 更新TableView的数据源方法
现在让TableView完全基于分组后的数据来展示:
override func viewDidLoad() { super.viewDidLoad() // 不用手动设置分组标题了,下载数据后自动生成 downloadJSON { self.tableView.reloadData() } } // 返回分组数量 func numberOfSections(in tableView: UITableView) -> Int { return sortedSectionTitles.count } // 返回每个分组的标题 func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { return sortedSectionTitles[section] } // 返回每个分组的条目数量 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { let sectionTitle = sortedSectionTitles[section] return groupedFigures[sectionTitle]?.count ?? 0 } // 配置每个cell的内容 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { // 替换成你的cell标识符 let cell = tableView.dequeueReusableCell(withIdentifier: "FigureCell", for: indexPath) let sectionTitle = sortedSectionTitles[indexPath.section] guard let figure = groupedFigures[sectionTitle]?[indexPath.row] else { return cell } // 这里配置cell的内容,比如: cell.textLabel?.text = figure.name cell.detailTextLabel?.text = figure.number return cell }
关键说明
- 用
[String: [FigureStats]]字典可以清晰地绑定分组标题和对应条目,避免数据重复 - 自动处理首字符的大小写和类型(字母/非字母),不用手动维护分组标题
- 所有数据源方法都基于分组后的数据,确保每个分组只显示自己的条目
内容的提问来源于stack exchange,提问作者Medicine Man
相关产品推荐
相关产品推荐

