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

iOS开发:UITableView无法展示Firebase数据,调用reloadData后单元格堆叠

问题原因&解决方案

你遇到的问题由两个核心错误导致,分别对应修改即可:

1. 单元格堆叠问题修复

堆叠根本原因是你没有给UITableView指定行高,同时自定义cell的子视图添加逻辑错误:

  • 先修改AssignmentCellTableViewCell,把子视图初始化从setSelected移到初始化方法,避免重复添加视图,同时避免变量名和系统属性冲突:
import UIKit

class AssignmentCellTableViewCell: UITableViewCell {
    
    lazy var backview: UIView = {
        let view = UIView(frame: CGRect(x: 10, y: 6, width: 340, height: 110))
        view.backgroundColor = UIColor.white
        return view
    }()
    
    lazy var customImageView: UIImageView = {
        let image = UIImageView(frame: CGRect(x: 4, y: 15, width: 80, height: 80))
        image.contentMode = .scaleAspectFill
        return image
    }()
    
    lazy var assignmentname: UILabel = {
        let assignmentname = UILabel(frame: CGRect(x: 116, y: 8, width: backview.frame.width - 88, height: 25))
        assignmentname.textAlignment = .left
        assignmentname.font = UIFont.boldSystemFont(ofSize: 20)
        return assignmentname
    }()
    
    lazy var duedate: UILabel = {
        let duedate = UILabel(frame: CGRect(x: 116, y: 42, width: backview.frame.width - 88, height: 25))
        duedate.textAlignment = .left
        duedate.font = UIFont.systemFont(ofSize: 10)
        return duedate
    }()

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        setupSubviews()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setupSubviews()
    }
    
    private func setupSubviews() {
        contentView.addSubview(backview)
        backview.addSubview(customImageView)
        backview.addSubview(assignmentname)
        backview.addSubview(duedate)
        backgroundColor = .clear
        contentView.backgroundColor = .clear
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        // 适配不同屏幕宽度
        backview.frame = CGRect(x: 10, y: 6, width: contentView.bounds.width - 20, height: 110)
        backview.layer.cornerRadius = 15
        backview.clipsToBounds = true
        backview.layer.borderColor = UIColor.systemGray5.cgColor
        backview.layer.borderWidth = 1
        customImageView.layer.cornerRadius = 40
        customImageView.clipsToBounds = true
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)
        // 移除原有addSubview逻辑
    }
}
  • 然后在setTableView方法里添加行高配置:
func setTableView() {
    assignmentstableview.backgroundColor = UIColor.clear
    assignmentstableview.delegate = self
    assignmentstableview.dataSource = self
    // 固定行高和你自定义cell的总高度匹配:6+110+6=122
    assignmentstableview.rowHeight = 122
    assignmentstableview.estimatedRowHeight = 0
    assignmentstableview.register(AssignmentCellTableViewCell.self, forCellReuseIdentifier: "Cell")
}

2. Firebase数据拉取逻辑修复

你原来的逻辑在循环遍历每条Firebase数据时都调用reloadData和setTableView,会导致多次重复刷新,同时viewDidAppear重复调用syncAssignments会导致数据重复,修改如下:

  • 首先调整viewDidLoad执行顺序,先配置TableView再加载数据:
override func viewDidLoad() {
    super.viewDidLoad()
    // 先配置TableView
    setTableView()
    // 测试数据可以保留
    data.append(assignmentmodal(name: "test2", duedate: "test2", imagename: ""))
    syncAssignments()
    // 原有其他逻辑不变
    titleLabel.text = "\(ClassesViewController.shared.chosenClass)"
    // ... 剩余原有代码不需要修改
}
  • 修改syncAssignments方法,先清空旧数据,全部加载完成后统一刷新:
func syncAssignments() {
    // 先清空旧数据避免重复
    self.data.removeAll()
    db.collection("Classes").document(ClassesViewController.shared.chosenClass).collection("Assignments").getDocuments() { [weak self] (querySnapshot, err) in
        guard let self = self else { return }
        if let err = err {
            print("Error getting documents: \(err)")
        } else {
            // 先循环处理完全部数据
            for document in querySnapshot!.documents {
                if let name = document.get("name"), let duedate = document.get("due date") {
                    self.data.append(assignmentmodal(name: "\(name)", duedate: "\(duedate)", imagename: ""))
                }
            }
            // 切主线程统一刷新UI
            DispatchQueue.main.async {
                self.assignmentstableview.reloadData()
            }
        }
    }
}
  • 对应的cellForRowAt方法里修改图片属性名即可:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let assignments = data[indexPath.row]
    let cell = assignmentstableview.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! AssignmentCellTableViewCell
    cell.customImageView.image = UIImage(named: assignments.imagename)
    cell.assignmentname.text = assignments.name
    cell.duedate.text = assignments.duedate
    return cell
}

内容的提问来源于stack exchange,提问作者Kiran Lim

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.27 18:36:03