Swift MVC模式下自定义UIView内按钮如何绑定ViewController中的点击方法
问题原因
你报错的根本原因有两个:
- MyView内部没有持有MyViewController的实例对象,你直接传
MyViewController类作为target是无效的,addTarget需要的是方法所属的实例对象 showDeleteAlert是MyViewController的实例方法,作用域仅在MyViewController内部,MyView默认无法直接访问
可行实现方案
三种实现方案均符合MVC分层规范,可根据你的项目复杂度选择:
方案1:在ViewController中给按钮添加target(最简便)
不需要修改MyView的核心逻辑,只需要把addTarget的逻辑移到VC层即可,符合MVC的职责划分:VC负责处理交互事件,View只负责视图渲染。
修改后的MyView代码:
class MyView: UIView { // 删除原来错误的addTarget行,按钮只做自身样式配置 lazy var deleteButton: UIButton = { let button = UIButton() button.setTitle("delete", for: .normal) return button }() // 其余代码保持不变 }
修改后的MyViewController的viewDidLoad代码:
override func viewDidLoad() { super.viewDidLoad() view.addSubview(myView) myView.frame = CGRect(origin: .zero, size: view.bounds.size) // 新增这行,在VC层给按钮绑定点击事件 myView.deleteButton.addTarget(self, action: #selector(showDeleteAlert), for: .touchUpInside) // 其余代码保持不变 }
方案2:闭包回调(解耦性更强)
适合View的交互事件较多、需要统一管理的场景:
修改后的MyView代码:
class MyView: UIView { // 定义点击回调闭包 var deleteAction: (() -> Void)? lazy var deleteButton: UIButton = { let button = UIButton() button.setTitle("delete", for: .normal) // target设为View自身,绑定View内部的方法 button.addTarget(self, action: #selector(deleteButtonClicked), for: .touchUpInside) return button }() @objc private func deleteButtonClicked() { // 触发回调 deleteAction?() } // 其余代码保持不变 }
修改后的MyViewController的viewDidLoad代码:
override func viewDidLoad() { super.viewDidLoad() view.addSubview(myView) myView.frame = CGRect(origin: .zero, size: view.bounds.size) // 给闭包赋值,处理点击逻辑,[weak self]避免循环引用 myView.deleteAction = { [weak self] in self?.showDeleteAlert() } // 其余代码保持不变 }
方案3:代理模式
适合交互逻辑复杂、多个事件需要统一协议约束的场景:
修改后的MyView代码:
// 定义代理协议 protocol MyViewDelegate: AnyObject { func didClickDeleteButton() } class MyView: UIView { // 定义弱引用代理属性,避免循环引用 weak var delegate: MyViewDelegate? lazy var deleteButton: UIButton = { let button = UIButton() button.setTitle("delete", for: .normal) button.addTarget(self, action: #selector(deleteButtonClicked), for: .touchUpInside) return button }() @objc private func deleteButtonClicked() { delegate?.didClickDeleteButton() } // 其余代码保持不变 }
修改后的MyViewController代码:
// 遵守MyViewDelegate协议 class MyViewController: UIViewController, MyViewDelegate { private var myView = MyView() override func viewDidLoad() { super.viewDidLoad() view.addSubview(myView) myView.frame = CGRect(origin: .zero, size: view.bounds.size) // 设置代理为当前VC myView.delegate = self // 其余代码保持不变 } @objc func showDeleteAlert() { print("showDelete is pressed") } // 实现代理方法 func didClickDeleteButton() { showDeleteAlert() } }
内容的提问来源于stack exchange,提问作者Yuuu
相关产品推荐
相关产品推荐

