UITableViewCell复用CAShapeLayer时图层残留及遍历异常问题求助
UITableViewCell复用CAShapeLayer残留问题解决方法
核心问题原因
你之前触发异常是因为直接遍历contentView.layer.sublayers的同时删除图层,这个数组是动态的,枚举过程中修改数组结构会导致CALayerArray was mutated while being enumerated错误。下面是几种可靠的解决方式:
方案一:用属性持有单个CAShapeLayer(最简洁)
在自定义UITableViewCell中声明一个属性专门持有当前的状态图层,每次刷新时先移除旧图层再创建新的:
import UIKit class CustomCell: UITableViewCell { // 持有当前的状态图层 var statusShapeLayer: CAShapeLayer? func configure(with status: Int) { // 先移除旧图层 statusShapeLayer?.removeFromSuperlayer() // 创建并配置新图层 let newLayer = CAShapeLayer() // 根据status设置不同的路径、颜色等 switch status { case 0: newLayer.path = UIBezierPath(rect: CGRect(x: 10, y: 10, width: 20, height: 20)).cgPath newLayer.fillColor = UIColor.red.cgColor case 1: newLayer.path = UIBezierPath(ovalIn: CGRect(x: 10, y: 10, width: 20, height: 20)).cgPath newLayer.fillColor = UIColor.green.cgColor default: newLayer.path = UIBezierPath(roundedRect: CGRect(x: 10, y: 10, width: 20, height: 20), cornerRadius: 4).cgPath newLayer.fillColor = UIColor.gray.cgColor } // 添加到contentView并更新持有引用 contentView.layer.addSublayer(newLayer) statusShapeLayer = newLayer } }
方案二:通过Tag标记图层,先收集再删除
如果需要同时管理多个同类型图层,可给图层设置固定Tag,先把要删除的图层收集到临时数组,再批量删除:
func configure(with status: Int) { // 定义状态图层的专属Tag let statusLayerTag = 1001 // 收集所有对应Tag的旧图层 let oldLayers = contentView.layer.sublayers?.filter { $0.tag == statusLayerTag } ?? [] // 批量删除 oldLayers.forEach { $0.removeFromSuperlayer() } // 创建新图层并设置Tag let newLayer = CAShapeLayer() newLayer.tag = statusLayerTag // 根据status配置图层... contentView.layer.addSublayer(newLayer) }
方案三:利用prepareForReuse提前清理(更符合复用生命周期)
重写Cell的prepareForReuse方法,在Cell被复用前主动清理旧图层,避免残留:
class CustomCell: UITableViewCell { var statusShapeLayer: CAShapeLayer? override func prepareForReuse() { super.prepareForReuse() // 清理旧图层 statusShapeLayer?.removeFromSuperlayer() statusShapeLayer = nil // 或者用Tag方式清理 // contentView.layer.sublayers?.filter { $0.tag == 1001 }.forEach { $0.removeFromSuperlayer() } } func configure(with status: Int) { // 直接创建并配置新图层即可,旧图层已被prepareForReuse清理 let newLayer = CAShapeLayer() // 根据status设置属性... contentView.layer.addSublayer(newLayer) statusShapeLayer = newLayer } }
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

