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

如何解决UICollectionViewCell偶尔无法加载内容的问题?

问题:水平UICollectionView随机出现单元格内容加载失败

我尝试在应用顶部实现一个小型水平UICollectionView,但每次启动应用时,总会有2-3个单元格无法加载内容,且无法加载的单元格是随机变化的。

ViewController实现代码

public var collectionViewDates = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())

override func viewDidLoad() {
    super.viewDidLoad()
    view.addSubview(collectionViewDates)
    collectionViewDates.frame = CGRect(x: 0,
                                       y: 90,
                                       width: view.width,
                                       height: 50)
}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return 30
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
     let cell = collectionView.dequeueReusableCell(withReuseIdentifier: DatesCollectionViewCell.identifier, for: indexPath) as! DatesCollectionViewCell
     cell.dateLabel.text = "I dag\(indexPath.row)"
     return cell
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: DatesCollectionViewCell.identifier, for: indexPath) as! DatesCollectionViewCell
    return CGSizeMake(cell.dateLabel.width + 30, collectionView.height)
}

自定义单元格代码

public var dateLabel: UILabel = {
        let label = UILabel()
        label.text = "I dag"
        label.adjustsFontSizeToFitWidth = true
        label.font = .systemFont(ofSize: 20, weight: .bold)
        label.backgroundColor = .systemBlue
        return label
    }()
    
override init(frame: CGRect) {
    super.init(frame: frame)
    addSubview(dateLabel)
    
    dateLabel.frame = CGRect(x: 0,
                             y: 0,
                             width: 50,
                             height: contentView.height)
    
    dateLabel.center.y = contentView.center.y
    dateLabel.center.x = contentView.center.x
}

required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
}

问题原因与修复方案

核心错误在于在sizeForItemAt布局方法中调用dequeueReusableCell,这会破坏UICollectionView的单元格复用逻辑,导致部分单元格被提前占用或初始化异常,最终出现随机的内容加载失败。

修复步骤:

  1. 替换sizeForItemAt的实现方式:
    不要通过复用单元格获取尺寸,直接根据文本内容计算宽度:

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        // 计算当前单元格要显示的文本宽度
        let text = "I dag\(indexPath.row)"
        let font = UIFont.systemFont(ofSize: 20, weight: .bold)
        let textWidth = text.size(withAttributes: [.font: font]).width
        // 加上预留的左右间距
        let cellWidth = textWidth + 30
        return CGSize(width: cellWidth, height: collectionView.height)
    }
    
  2. 修正单元格的布局逻辑:
    原单元格中手动设置frame的方式容易出现位置偏移,改用AutoLayout更可靠:

    public var dateLabel: UILabel = {
        let label = UILabel()
        label.text = "I dag"
        label.adjustsFontSizeToFitWidth = true
        label.font = .systemFont(ofSize: 20, weight: .bold)
        label.backgroundColor = .systemBlue
        // 关闭自动布局转换,启用约束
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        addSubview(dateLabel)
        
        // 添加约束确保label居中且有合适的边距
        NSLayoutConstraint.activate([
            dateLabel.centerYAnchor.constraint(equalTo: contentView.centerYAnchor),
            dateLabel.centerXAnchor.constraint(equalTo: contentView.centerXAnchor),
            dateLabel.leadingAnchor.constraint(greaterThanOrEqualTo: contentView.leadingAnchor, constant: 15),
            dateLabel.trailingAnchor.constraint(lessThanOrEqualTo: contentView.trailingAnchor, constant: -15),
            dateLabel.heightAnchor.constraint(equalTo: contentView.heightAnchor, multiplier: 0.8)
        ])
    }
    
  3. 确认单元格注册:
    确保在viewDidLoad中注册自定义单元格,否则会导致复用失败:

    override func viewDidLoad() {
        super.viewDidLoad()
        // 注册单元格
        collectionViewDates.register(DatesCollectionViewCell.self, forCellWithReuseIdentifier: DatesCollectionViewCell.identifier)
        view.addSubview(collectionViewDates)
        collectionViewDates.frame = CGRect(x: 0,
                                           y: 90,
                                           width: view.width,
                                           height: 50)
        // 设置代理与数据源
        collectionViewDates.dataSource = self
        collectionViewDates.delegate = self
    }
    

内容的提问来源于stack exchange,提问作者Kristoffer Melen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 23:45:31