使用UIContentConfiguration向可复用Cell传递UIView遇显示异常问题
UIContentConfiguration 添加自定义UIView显示不稳定的问题解决
问题根源分析
你的代码存在几个核心问题,直接导致视图显示不稳定:
- 值类型持有弱引用的生命周期问题:
ContentConfiguration是值类型struct,持有weak var myView: UIView?会导致引用计数管理混乱。当视图被复用、父层级变化或系统回收内存时,弱引用会意外变为nil,造成视图消失。 - configure方法逻辑漏洞:
- 重复添加视图:每次调用
configure时,只要myView存在就直接执行addSubview,未检查视图是否已在容器内,导致层级混乱。 - 缺少布局约束:添加的
myView未设置任何约束,即使成功添加也可能因尺寸为0或位置错误,看起来像是未显示。 - 移除逻辑不严谨:清空所有子视图后,若后续
myView的弱引用已失效,无法重新恢复视图。
- 重复添加视图:每次调用
修正后的代码实现
1. 修正配置结构体(移除弱引用,实现必要协议)
struct ContentConfiguration: UIContentConfiguration { // 改用强引用持有视图实例,由外部管理视图生命周期 var myView: UIView? func makeContentView() -> UIView & UIContentView { MyContentView(configuration: self) } // 必须实现UIContentConfiguration要求的更新方法 func updated(for state: UIConfigurationState) -> ContentConfiguration { var copy = self // 若需根据状态(如选中、高亮)更新配置,可在此处理 return copy } }
2. 修正ContentView逻辑(规范视图添加/移除流程)
class MyContentView: UIView, UIContentView { private let containerView: UIView = { let view = UIView() view.translatesAutoresizingMaskIntoConstraints = false return view }() private var currentConfiguration: ContentConfiguration init(configuration: ContentConfiguration) { self.currentConfiguration = configuration super.init(frame: .zero) setupContainerLayout() configure(with: configuration) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } private func setupContainerLayout() { addSubview(containerView) // 固定容器视图铺满整个contentView NSLayoutConstraint.activate([ containerView.topAnchor.constraint(equalTo: topAnchor), containerView.leadingAnchor.constraint(equalTo: leadingAnchor), containerView.trailingAnchor.constraint(equalTo: trailingAnchor), containerView.bottomAnchor.constraint(equalTo: bottomAnchor) ]) } func configure(with configuration: UIContentConfiguration) { guard let config = configuration as? ContentConfiguration else { return } defer { currentConfiguration = config } // 先清空容器内所有子视图,避免层级混乱 containerView.subviews.forEach { $0.removeFromSuperview() } guard let targetView = config.myView else { return } // 添加目标视图并设置布局约束 containerView.addSubview(targetView) targetView.translatesAutoresizingMaskIntoConstraints = false // 根据业务需求调整约束,示例为铺满容器 NSLayoutConstraint.activate([ targetView.topAnchor.constraint(equalTo: containerView.topAnchor), targetView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor), targetView.trailingAnchor.constraint(equalTo: containerView.trailingAnchor), targetView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor) ]) } // 实现UIContentView要求的configuration属性 var configuration: UIContentConfiguration { get { currentConfiguration } set { guard let newConfig = newValue as? ContentConfiguration else { return } configure(with: newConfig) } } }
关键注意事项
- 避免配置持有视图弱引用:UIView的生命周期应由父视图/视图控制器管理,配置仅负责传递显示所需的视图实例。更推荐的方式是在配置中定义视图创建闭包(如
var makeMyView: () -> UIView?),避免直接持有视图实例。 - 确保视图布局完整性:所有添加的自定义视图必须设置明确的约束,否则会因无布局规则导致显示异常。
- 严格控制视图层级:每次configure时先清空容器内的旧视图,确保新视图是唯一的子视图,避免重复添加导致的层级冲突。
内容的提问来源于stack exchange,提问作者Tudor Neagu
相关产品推荐
相关产品推荐

