Swift4下Firebase数据TableView首字母分组排序及跳转数据混乱问题
解决词典App的TableView数据混乱与首字母分组问题
嘿,我来帮你搞定这两个头疼的问题——跳转页面后数据混乱,还有首字母分组显示的需求,完全适配你用的Xcode10.3 + Swift4环境!
一、先解决跳转后数据混乱的问题
你现在在cellForRowAt里实时排序fizikListe,这可是个大坑!cellForRowAt会被系统频繁调用(比如滑动TableView、页面刷新时),每次调用都排序的话,数组会被反复打乱,跳转回来后自然就乱了。
正确的做法是:只在数据加载完成/更新的时候排序一次,维护一个专门的排序后数组,而不是直接修改原始数据数组。
具体实现步骤:
- 在你的
ViewController2里,除了原始的fizikListe,再声明一个排序后的数组:
var fizikListe: [FizikSozluk] = [] var sortedFizikListe: [FizikSozluk] = [] // 专门存排序后的数据
- 当你从Firebase拉取到数据后,只在这时候对数组排序一次,比如在Firebase的回调里:
// 假设这是你从Firebase获取数据的回调 func fetchDataFromFirebase() { // ... 你的Firebase数据获取代码 ... // 数据获取完成后,先排序再赋值给sortedFizikListe sortedFizikListe = fizikListe.sorted { // 按baslik的字母顺序排序,统一转成小写避免大小写分组错误 $0.baslik.lowercased() < $1.baslik.lowercased() } tableView.reloadData() }
- 然后在
cellForRowAt里直接用sortedFizikListe,不要再在这里排序了:
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "YourCellID", for: indexPath) as! YourCellType let fizik = sortedFizikListe[indexPath.row] cell.titleLabel.text = fizik.baslik // ... 其他cell配置代码 ... return cell }
这样不管怎么跳转页面,只要数据没更新,sortedFizikListe就不会被重新排序,自然不会混乱啦!
二、实现首字母分组显示
接下来咱们搞首字母分组,需要先把排序后的数组按首字母分组,生成两个关键数组:一个存分组的首字母(作为section标题),一个存每个section对应的模型数组。
具体实现步骤:
- 在
ViewController2里添加两个分组相关的数组:
var sectionTitles: [String] = [] // 存每个section的首字母 var sectionData: [[FizikSozluk]] = [] // 存每个section对应的模型数组
- 在数据排序完成后,添加分组逻辑:
func fetchDataFromFirebase() { // ... 先获取原始数据,排序得到sortedFizikListe ... // 开始分组 // 先按首字母分组,用字典来暂存:key是首字母,value是对应模型数组 var groupedDictionary: [String: [FizikSozluk]] = [:] for fizik in sortedFizikListe { // 提取baslik的首字母,转成大写统一格式 guard let firstChar = fizik.baslik.first?.uppercased() else { // 如果标题为空,放到"#"分组里(可选,你可以自己定义) groupedDictionary["#", default: []].append(fizik) continue } groupedDictionary[firstChar, default: []].append(fizik) } // 把字典的key排序,得到有序的section标题 sectionTitles = groupedDictionary.keys.sorted() // 根据排序后的标题,生成对应的section数据数组 sectionData = sectionTitles.map { groupedDictionary[$0]! } tableView.reloadData() }
- 修改TableView的代理方法来支持分组:
// 返回section的数量 override func numberOfSections(in tableView: UITableView) -> Int { return sectionTitles.count } // 返回每个section的行数 override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return sectionData[section].count } // 设置section的标题 override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { return sectionTitles[section] } // 修改cellForRowAt,从sectionData里取数据 override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "YourCellID", for: indexPath) as! YourCellType let fizik = sectionData[indexPath.section][indexPath.row] cell.titleLabel.text = fizik.baslik // ... 其他cell配置代码 ... return cell }
- 可选:如果想要右侧的索引条(就是快速跳转的字母条),实现这个方法:
override func sectionIndexTitles(for tableView: UITableView) -> [String]? { return sectionTitles }
最后再提醒几点
- 记得处理
baslik为空的情况,我上面是放到了"#"分组里,你可以根据需求调整; - 统一用
uppercased()或者lowercased()处理首字母,避免"A"和"a"分成两个不同的组; - 如果Firebase的数据是实时更新的,记得在数据变化的回调里重新执行排序和分组逻辑,然后刷新TableView。
这样下来,不仅跳转页面后数据不会混乱,还能完美实现首字母分组显示的效果啦!
内容的提问来源于stack exchange,提问作者orhangulusen
相关产品推荐
相关产品推荐

