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

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
    }
错误分析
  1. 数据结构逻辑错误:原代码将回复数据存入独立的replyArray,但API中回复是嵌套在对应评论的reply字段里的,应该直接从每个评论对象中获取回复,不需要单独的replyArray。
  2. 分区行数计算错误:numberOfRowsInSection返回全局replyArray的长度,而非当前分区对应评论的回复数量。
  3. 单元格数据取值错误:cellForRowAt中用indexPath.section取replyArray数据,逻辑完全错误,应根据当前分区的评论,取其回复列表中indexPath.row位置的数据。
  4. 缺少分区头部实现:原代码未实现viewForHeaderInSection方法,无法将评论显示为分区头部。
  5. 重复添加手势:在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 13:14:59