如何解决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的单元格复用逻辑,导致部分单元格被提前占用或初始化异常,最终出现随机的内容加载失败。
修复步骤:
替换
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) }修正单元格的布局逻辑:
原单元格中手动设置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) ]) }确认单元格注册:
确保在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
相关产品推荐
相关产品推荐

