iOS桌游追踪应用TextView代理触发Segue重复执行问题排查
解决TextView触发Segue执行两次的问题
你的问题根源在于textViewShouldBeginEditing代理方法可能被UIKit多次调用(比如系统内部状态更新、快速重复点击等场景),导致performSegue被执行多次。下面提供两种更优雅的解决方案,比时间判断的临时方法更可靠:
方法一:添加执行标记防止重复触发
通过一个布尔变量标记Segue是否正在执行,避免重复调用。
步骤1:添加实例变量
在你的AddMatchViewController中添加一个私有变量:
private var isSegueInProgress = false
步骤2:修改代理方法
更新textViewShouldBeginEditing,先检查标记再执行Segue:
func textViewShouldBeginEditing(_ textView: UITextView) -> Bool { // 如果Segue正在执行,直接返回false guard !isSegueInProgress else { return false } isSegueInProgress = true // 原来的SegueKey赋值逻辑 if textView == playersNameView { segueKey = "all" } else if textView == winnersNameView { segueKey = "winners" } else if textView == loosersNameView { segueKey = "loosers" } // 执行Segue的逻辑 if textView == pointsView { performSegue(withIdentifier: "addPoints", sender: self) } else if [playersNameView, winnersNameView, loosersNameView].contains(textView) { performSegue(withIdentifier: "choosePlayers", sender: self) } return false }
步骤3:重置标记
当从子页面返回时,重置标记以允许再次触发Segue,在viewWillAppear中添加:
override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) isSegueInProgress = false }
方法二:用Tap手势替代代理方法(推荐)
直接给TextView添加点击手势,完全避开代理方法的不确定性,逻辑更可控。
步骤1:添加Tap手势
在viewDidLoad中给每个需要触发Segue的TextView添加手势:
override func viewDidLoad() { super.viewDidLoad() // 为playersNameView添加点击手势 let playersTap = UITapGestureRecognizer(target: self, action: #selector(handlePlayersTap)) playersNameView.addGestureRecognizer(playersTap) playersNameView.isUserInteractionEnabled = true // 为winnersNameView添加点击手势 let winnersTap = UITapGestureRecognizer(target: self, action: #selector(handleWinnersTap)) winnersNameView.addGestureRecognizer(winnersTap) winnersNameView.isUserInteractionEnabled = true // 为loosersNameView添加点击手势 let loosersTap = UITapGestureRecognizer(target: self, action: #selector(handleLoosersTap)) loosersNameView.addGestureRecognizer(loosersTap) loosersNameView.isUserInteractionEnabled = true // 为pointsView添加点击手势 let pointsTap = UITapGestureRecognizer(target: self, action: #selector(handlePointsTap)) pointsView.addGestureRecognizer(pointsTap) pointsView.isUserInteractionEnabled = true }
步骤2:实现手势响应方法
添加对应的Selector方法处理点击事件:
@objc private func handlePlayersTap() { segueKey = "all" performSegue(withIdentifier: "choosePlayers", sender: self) } @objc private func handleWinnersTap() { segueKey = "winners" performSegue(withIdentifier: "choosePlayers", sender: self) } @objc private func handleLoosersTap() { segueKey = "loosers" performSegue(withIdentifier: "choosePlayers", sender: self) } @objc private func handlePointsTap() { performSegue(withIdentifier: "addPoints", sender: self) }
步骤3:移除代理方法
现在可以删除textViewShouldBeginEditing代理方法了,因为所有触发逻辑都由Tap手势接管。
两种方法对比
- 方法一:改动小,适合快速修复现有代码,保留代理方法的逻辑结构。
- 方法二:更彻底,完全避免了UIKit代理方法的潜在多次调用问题,代码逻辑更清晰,推荐作为长期解决方案。
内容的提问来源于stack exchange,提问作者Przemysław Szafulski
相关产品推荐
相关产品推荐

