使用[String: [String]]字典作为UITableView数据源的行数据匹配问题
解决UITableView中字典数据源的键值关联问题
你现在遇到的核心问题是数据结构和UITableView的数据源逻辑不匹配:你把所有descContent的元素合并到了requestedList里,而keyArr是每个header的集合,两者长度完全不同,用同一个indexPath.row去索引这两个数组,必然会出现键值错位的情况。
正确的做法是把UITableView改成分组结构,每个Section对应一个header(字典的key),每个Section里的Row对应该key对应的descContent数组元素。这样就能完美关联键和对应的值了,具体修改如下:
1. 精简数据变量
我们只需要保留有序的key数组和字典即可,requestedList可以直接删掉——因为我们不需要再把所有元素合并在一起:
var keyArr = [String]() // 维护Section的顺序,每个元素对应一个header var requestedDictionary = [String: [String]]() // 存储header对应的descContent数组
2. 数据查询部分(小幅度优化)
原来的查询逻辑是对的,我们只需要去掉requestedList的填充,同时加上安全解包避免崩溃,最后记得刷新表视图:
let tQuery = PFQuery(className: "MyClass") tQuery.whereKey("username", equalTo: PFUser.current()?.username as Any) tQuery.selectKeys(["descContent", "header"]) do { let returnedObjects = try tQuery.findObjects() for object in returnedObjects { guard let header = object["header"] as? String else { continue } keyArr.append(header) if let descArr = object["descContent"] as? [String] { requestedDictionary[header] = descArr } } // 查询完成后刷新表视图 tableView.reloadData() } catch { print("查询出错: \(error.localizedDescription)") }
3. 修改UITableView数据源方法
现在我们按Section来对应每个header,Row对应数组元素:
3.1 设置Section数量
每个Section对应一个header:
func numberOfSections(in tableView: UITableView) -> Int { return keyArr.count }
3.2 设置每个Section的Row数量
取当前Section对应的header,返回对应数组的长度:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { let currentHeader = keyArr[section] return requestedDictionary[currentHeader]?.count ?? 0 }
3.3 配置Cell内容
现在可以正确获取当前Row对应的descContent元素,以及它所属的header:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "RequestViewCell", for: indexPath) as! RequestViewCell // 获取当前Section对应的header和数组 let currentHeader = keyArr[indexPath.section] guard let descArr = requestedDictionary[currentHeader], indexPath.row < descArr.count else { return cell } let currentDesc = descArr[indexPath.row] // 配置Cell文本 cell.descLbl.text = "Your ticket has been requested by \(currentDesc)" cell.refLbl.text = "for: \(currentHeader)" // 按钮Tag:用section+row组合,避免不同Section的Row Tag冲突 cell.leftBtn.tag = indexPath.section * 1000 + indexPath.row cell.leftBtn.addTarget(self, action: #selector(leftClick(sender:)), for: .touchUpInside) cell.rightBtn.tag = indexPath.section * 1000 + indexPath.row cell.rightBtn.addTarget(self, action: #selector(rightClick(sender:)), for: .touchUpInside) return cell }
3.4 可选优化:添加Section Header
如果想在每个Section顶部显示对应的header,可以实现这个方法:
func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { return keyArr[section] }
为什么原来的方法会出错?
举个例子:假设你从Parse拿到2个对象,第一个对象的header是"Header A",对应descContent有3个元素;第二个对象的header是"Header B",对应descContent有2个元素。那么:
keyArr的长度是2,元素是["Header A", "Header B"]requestedList的长度是5,元素是[A1, A2, A3, B1, B2]
当indexPath.row=1时,requestedList[1]是A2,但keyArr[1]是Header B,这就导致了错误的关联,而分组的方式就能彻底避免这个问题。
内容的提问来源于stack exchange,提问作者dpat0074
相关产品推荐
相关产品推荐

