拆分UIViewController子类后UITapGesture无法识别,求解决办法
解决拆分子类后UITapGestureRecognizer无法识别的问题
嘿,我一眼就看出问题出在哪了——你在MyViewController的viewDidLoad里创建的SubclassMyViewController实例是个临时局部对象!执行完setupUserInterface之后,这个子类实例就被系统回收销毁了。而你给logoImage加的手势,target指向的就是这个已经被释放的子类对象,所以点击的时候根本找不到能响应方法的对象,自然没反应。
给你两个可行的解决方案,按需选择:
方案一:让子类自己管理UI和响应逻辑(推荐)
这种方式更符合单一职责原则,把UI元素和对应的点击逻辑都放在子类里,耦合性更低:
// MyViewController.swift class MyViewController: UIViewController { // 保存子类实例,确保它不会被提前释放 private let subVC = SubclassMyViewController() override func viewDidLoad() { super.viewDidLoad() subVC.setupUserInterface(view: view) } } // SubclassMyViewController.swift class SubclassMyViewController: MyViewController { func setupUserInterface(view: UIView) { view.addSubview(logoImage) logoImage.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true logoImage.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true logoImage.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.5).isActive = true } lazy var logoImage: UIImageView = { let imageView = UIImageView() imageView.image = UIImage(named: "logo") imageView.translatesAutoresizingMaskIntoConstraints = false imageView.contentMode = .scaleAspectFit imageView.isUserInteractionEnabled = true // 手势target指向子类自己,因为doSomething现在在子类里 let tap = UITapGestureRecognizer(target: self, action: #selector(doSomething)) imageView.addGestureRecognizer(tap) return imageView }() @objc func doSomething() { log.info("logo was tapped") } }
方案二:如果响应逻辑必须留在父类
要是点击后的逻辑必须放在MyViewController里,那你需要让手势的target指向存活的父类实例,同时确保子类实例不被释放:
// MyViewController.swift class MyViewController: UIViewController { private let subVC = SubclassMyViewController() override func viewDidLoad() { super.viewDidLoad() // 把父类实例传给子类 subVC.setupUserInterface(view: view, parentVC: self) } @objc func doSomething() { log.info("logo was tapped") } } // SubclassMyViewController.swift class SubclassMyViewController: MyViewController { // 新增参数接收父类实例 func setupUserInterface(view: UIView, parentVC: MyViewController) { view.addSubview(logoImage) logoImage.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true logoImage.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true logoImage.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.5).isActive = true // 更新手势的target为传入的父类实例 let tap = UITapGestureRecognizer(target: parentVC, action: #selector(parentVC.doSomething)) logoImage.addGestureRecognizer(tap) } lazy var logoImage: UIImageView = { let imageView = UIImageView() imageView.image = UIImage(named: "logo") imageView.translatesAutoresizingMaskIntoConstraints = false imageView.contentMode = .scaleAspectFit imageView.isUserInteractionEnabled = true return imageView }() }
关键总结
无论选哪种方案,核心都是确保手势的target指向一个没有被释放的对象,同时不要让子类实例成为临时对象被系统回收。方案一更推荐,因为它让代码职责更清晰,后期维护起来也更方便。
内容的提问来源于stack exchange,提问作者Tyrus Rechs
相关产品推荐
相关产品推荐

