iOS Swift带分区UITableView数据显示异常,求正确实现代码
问题描述
开发App时需要实现带分区的UITableView,要求将评论作为分区头部,对应的回复显示为分区内的单元格。现有两个数组commentArr(存储评论数据)、replyArray(存储回复数据),API响应数据如下:
"posts_review": [ { "id": "87", "name": "Pr****ha", "email": "test@gmail.com", "comment":"\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\uFFFD", "post_id": "357", "created_at": "2023-05-29 05:57:11", "rating": null, "user_id": "1405", "status": "1", "review_id": "0", "reply": [], "image": "image1683887192.png" }, { "id": "71", "name": "sidd", "email": "ab@abc.com", "comment": "hello", "post_id": "357", "created_at": "2023-05-27 09:22:02", "rating": null, "user_id": "469", "status": "1", "review_id": "0", "reply": [ { "id": "78", "name": "Ab*****ap", "email": null, "comment": "test reply....2", "post_id": null, "created_at": "2023-05-29 03:06:17", "rating": null, "user_id": "464", "status": "1", "review_id": "71", "image": "image1675080770.jpg" }, { "id": "92", "name": "sha", "email": null, "comment": null, "post_id": null, "created_at": "2023-05-29 06:12:18", "rating": null, "user_id": "1405", "status": "1", "review_id": "71", "image": "image1683887192.png" } ], "image": "image1683887192.png" }, { "id": "64", "name": "Ab******ap", "email": "ab@abc.com", "comment": "This is test", "post_id": "357", "created_at": "2023-05-25 01:05:57", "rating": null, "user_id": "464", "status": "1", "review_id": "0" }, { "id": "63", "name": "Ab.......", "email": "ab@abc.com", "comment": "This is test", "post_id": "357", "created_at": "2023-05-25 01:05:53", "rating": null, "user_id": "464", "status": "1", "review_id": "0", "reply": [], "image": "image1675080770.jpg" } ]
尝试了以下代码但数据显示异常,需要正确的UITableView实现代码:
func numberOfSections(in tableView: UITableView) -> Int { print("CommentArray Count is --", self.commentArr.count) return self.commentArr.count } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { print("replyArray Count is --", self.replyArray.count) return self.replyArray.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = commentTable.dequeueReusableCell(withIdentifier: "CommenrTVC") as! CommenrTVC let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(self.dismissKeyboard)) tap.cancelsTouchesInView = false self.commentTable.addGestureRecognizer(tap) cell.nameLbl.text = self.replyArray[indexPath.section]["name"].string ?? "" let dateStr = self.replyArray[indexPath.section]["created_at"].string ?? "" cell.dateLbl.text = dateStr //cell.commentLbl.text = self.commentArr[indexPath.row]["comment"].string ?? "" let commentStrr = self.replyArray[indexPath.section]["comment"].string ?? "" return cell }
错误分析
- 数据结构逻辑错误:原代码将回复数据存入独立的
replyArray,但API中回复是嵌套在对应评论的reply字段里的,应该直接从每个评论对象中获取回复,不需要单独的replyArray。 - 分区行数计算错误:
numberOfRowsInSection返回全局replyArray的长度,而非当前分区对应评论的回复数量。 - 单元格数据取值错误:
cellForRowAt中用indexPath.section取replyArray数据,逻辑完全错误,应根据当前分区的评论,取其回复列表中indexPath.row位置的数据。 - 缺少分区头部实现:原代码未实现
viewForHeaderInSection方法,无法将评论显示为分区头部。 - 重复添加手势:在
cellForRowAt中重复添加点击手势,会导致多次绑定,应移到初始化方法中执行一次。
正确实现代码
第一步:定义数据模型(用结构体替代字典,提升类型安全性)
// 回复数据模型 struct ReplyModel: Codable { let id: String let name: String? let email: String? let comment: String? let createdAt: String let image: String? enum CodingKeys: String, CodingKey { case id, name, email, comment, image case createdAt = "created_at" } } // 评论数据模型 struct CommentModel: Codable { let id: String let name: String let email: String? let comment: String? let createdAt: String let image: String? let reply: [ReplyModel] enum CodingKeys: String, CodingKey { case id, name, email, comment, image, reply case createdAt = "created_at" } } // 替换原有commentArr为类型安全的数组 var comments: [CommentModel] = []
第二步:解析API响应数据
// 假设已获取到API返回的json字符串或Data if let jsonData = apiResponseData { do { // 解析JSON数据到模型数组 let responseDict = try JSONDecoder().decode([String: [CommentModel]].self, from: jsonData) comments = responseDict["posts_review"] ?? [] commentTable.reloadData() } catch { print("数据解析失败:\(error.localizedDescription)") } }
第三步:UITableView代理与数据源实现
// 分区数量等于评论总数 func numberOfSections(in tableView: UITableView) -> Int { return comments.count } // 每个分区的行数等于对应评论的回复数量 func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return comments[section].reply.count } // 实现分区头部,显示评论内容 func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { // 自定义评论头部视图,需提前注册复用标识符"CommentHeaderView" let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "CommentHeaderView") as! CommentHeaderView let comment = comments[section] headerView.nameLabel.text = comment.name headerView.dateLabel.text = comment.createdAt headerView.commentLabel.text = comment.comment ?? "" // 头像图片加载逻辑根据需求自行实现 // if let imageUrlStr = comment.image { ... } return headerView } // 设置头部自动计算高度(需在HeaderView中配置正确的自动布局约束) func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { return UITableView.automaticDimension } // 回复单元格配置 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "CommenrTVC", for: indexPath) as! CommenrTVC // 获取当前分区的评论及对应行的回复 let comment = comments[indexPath.section] let reply = comment.reply[indexPath.row] cell.nameLbl.text = reply.name ?? "" cell.dateLbl.text = reply.createdAt cell.commentLbl.text = reply.comment ?? "" // 回复头像加载逻辑根据需求自行实现 // if let imageUrlStr = reply.image { ... } return cell } override func viewDidLoad() { super.viewDidLoad() // 注册单元格和头部视图 commentTable.register(UINib(nibName: "CommenrTVC", bundle: nil), forCellReuseIdentifier: "CommenrTVC") commentTable.register(UINib(nibName: "CommentHeaderView", bundle: nil), forHeaderFooterViewReuseIdentifier: "CommentHeaderView") // 添加一次点击收起键盘的手势 let tap = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard)) tap.cancelsTouchesInView = false commentTable.addGestureRecognizer(tap) } @objc func dismissKeyboard() { view.endEditing(true) }
补充说明
- 需自行创建
CommentHeaderView,包含显示评论姓名、日期、内容的控件,并配置好自动布局约束以支持高度自适应。 - 使用Codable模型可以避免字典取值的类型转换风险,减少潜在崩溃。
内容的提问来源于stack exchange,提问作者Abhinandan Pratap
相关产品推荐
相关产品推荐

