UIButton选择器失效排查:导航控制器子视图内按钮无响应
你猜的没错,addTarget里的target设置确实可能是问题根源,但还有几个容易踩的坑也会导致这个情况,我帮你逐一梳理:
方法未添加
@objc修饰
Swift 的方法默认不会暴露给 Objective-C 运行时,而 UIButton 的点击事件是依赖 Objective-C 消息机制的。如果你的handleReminderSetBtn和handleReminderCancelBtn没加@objc关键字,系统根本找不到对应的方法,自然不会触发点击逻辑。正确的写法应该是这样:
@objc func handleReminderSetBtn() { // 你的按钮点击逻辑 } @objc func handleReminderCancelBtn() { // 你的按钮点击逻辑 }这是最常见的原因,优先检查这个!
懒加载闭包的
self捕获问题
你用闭包初始化按钮时,直接在闭包里引用self,虽然懒加载属性的闭包是在self初始化完成后才执行的,但如果没有明确处理捕获列表,可能会出现循环引用或者self指向异常的情况。建议在闭包中添加弱引用捕获,避免潜在问题:var setButton: UIButton = { [weak self] in // 添加弱引用捕获 var button = UIButton(type: .system) button.setTitle("Done", for: .normal) button.tintColor = .white button.addTarget(self, action: #selector(handleReminderSetBtn), for: .touchUpInside) return button }()不过你提到 UIPickerView 能正常工作,说明视图实例还在内存中,这个问题的概率相对低,但加上捕获列表能避免后续的内存泄漏问题。
按钮没有设置有效可点击区域
你的代码里只给按钮设置了标题和 tintColor,完全没设置 frame 或者 Auto Layout 约束!如果按钮的 frame 是默认的CGRect.zero,那它的可点击区域就是0——看起来有文字,但实际点击不到任何东西。你需要给按钮设置尺寸和位置,比如:
var setButton: UIButton = { var button = UIButton(type: .system) button.setTitle("Done", for: .normal) button.tintColor = .white button.addTarget(self, action: #selector(handleReminderSetBtn), for: .touchUpInside) button.translatesAutoresizingMaskIntoConstraints = false // 开启Auto Layout支持 return button }()然后在 CardReminder1 的
viewDidLoad方法里添加约束,把按钮固定到合适的位置:NSLayoutConstraint.activate([ setButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -20), setButton.topAnchor.constraint(equalTo: view.topAnchor, constant: 20), setButton.widthAnchor.constraint(equalToConstant: 80), setButton.heightAnchor.constraint(equalToConstant: 40) ])父视图的交互被禁用
虽然 UIPickerView 能正常工作,但还是快速确认一下:cardreminder1、viewOverLay 这些父视图的isUserInteractionEnabled是不是true。如果某个父视图的这个属性被设为false,所有子视图的交互都会被屏蔽。你可以在调试时打印一下:print("cardreminder1 interaction: \(cardreminder1.isUserInteractionEnabled)") print("viewOverLay interaction: \(viewOverLay.isUserInteractionEnabled)")
按照这个顺序排查,大概率能解决问题!
内容的提问来源于stack exchange,提问作者Osama Naeem

