自定义View中let初始化的UIButton点击事件不生效但VC中可用?
问题根因
该问题本质是Swift类属性初始化时序和self可用性的差异导致的:
let修饰的存储属性必须在类实例初始化完成前完成赋值,它的初始化闭包执行时,当前类的实例(即self)还未完成初始化,实际值为nil。此时调用addTarget传入的响应目标为空,按钮点击后没有对应的接收者处理事件,自然无法触发回调。lazy var修饰的延迟加载属性,仅会在属性第一次被访问时才执行初始化闭包,此时类实例已经完成初始化,self是有效实例,addTarget可以正确绑定响应目标,点击事件即可正常触发。
你问题中提到的异常代码如下:
private let usernameButton: UIButton = { let button = UIButton(type: .system) button.setTitleColor(.black, for: .normal) button.setTitle("someTitle", for: .normal) button.titleLabel?.font = .boldSystemFont(ofSize: 13) button.addTarget(self, action: #selector(didTapUsername), for: .touchUpInside) return button }()
为什么UIViewController中相同let写法看似可用?
这属于不稳定的异常表现,并非符合逻辑的正常行为:
- 多数情况是测试场景存在偏差,比如ViewController中的按钮初始化代码实际写在
viewDidLoad等生命周期方法中,此时ViewController实例已经完成初始化,self有效,所以事件可以正常响应。 - 少数情况是UIKit runtime的兼容机制巧合让事件找到了响应目标,但该逻辑不可靠,不建议依赖。
规范写法
如果需要在属性初始化闭包中访问self(比如绑定事件、依赖当前实例的属性做配置),必须使用lazy var声明该属性,保证初始化时序正确。
内容的提问来源于stack exchange,提问作者user15572366
相关产品推荐
相关产品推荐

