为何UICollectionViewCell中代码创建的按钮需设为lazy var?
为什么UICollectionViewCell里的按钮要用lazy var而非常量?
这个问题核心在于Swift中属性初始化时机和self的可用性,我给你一步步拆解清楚:
用let定义按钮时的问题
当你用let xButton: UIButton = { ... }()这种立即执行闭包的方式定义常量时:
- 这个闭包会在Cell实例初始化的最早期阶段就运行——此时Cell的所有存储属性还没完成赋值,整个实例都还没构建完成,
self处于未完全初始化的状态。 - 你在闭包里调用
button.addTarget(self, ...)时,这里的self并不是一个有效的、完整的Cell实例,相当于按钮的target绑定了一个无效引用,所以点击按钮时根本找不到要执行的handleX方法,自然不会打印"123"。
换成lazy var后正常工作的原因
lazy var的核心特性就是延迟初始化:
- 它的初始化闭包只会在你第一次访问这个属性的时候才会执行,这时候Cell实例已经完成了所有初始化步骤,
self是一个完全有效的、已经构建好的对象。 - 这时候再给按钮绑定
self作为target,就能正确关联到当前Cell实例,点击按钮时系统就能找到对应的handleX方法并触发执行。
补充验证小技巧
你可以在两种初始化方式的闭包里加一句print(self),就能直观看到差异:
- 用
let时,打印出来的self是nil或者未初始化的占位值; - 用
lazy var时,打印出来的是正常的Cell实例地址。
修正后的示例代码
class Cell: UICollectionViewCell { // 用lazy var确保初始化时self已就绪 lazy var xButton: UIButton = { let button = UIButton(type: .system) button.addTarget(self, action: #selector(handleX), for: .touchUpInside) return button }() @objc func handleX() { print("123") } override init(frame: CGRect) { super.init(frame: frame) // 第一次访问xButton,触发lazy初始化 contentView.addSubview(xButton) // 添加AutoLayout约束示例 xButton.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ xButton.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 8), xButton.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -8), xButton.widthAnchor.constraint(equalToConstant: 30), xButton.heightAnchor.constraint(equalToConstant: 30) ]) } required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } }
内容的提问来源于stack exchange,提问作者leedex
相关产品推荐
相关产品推荐

