You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 07:06:44