You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FirstVC与SecondVC二次交互异常:按钮触发问题求助

Hey there! Let's break down why your SecondVC button is misbehaving on the second run and fix it step by step. This is a super common issue when dealing with view controller data passing, so let's go through the most likely causes and solutions:

1. Fix Closure Retain Cycles (The #1 Culprit)

If you're using a closure to pass data back to FirstVC, a strong reference cycle is probably stopping your view controllers from being properly destroyed after the first use. This means the second time you open SecondVC, the old closure (or a broken reference) is still hanging around.

Solution:

Always use [weak self] (or [unowned self] if you're 100% sure the reference won't be nil) in your completion closure to avoid retaining FirstVC indefinitely:

// In FirstVC's textFieldDidBeginEditing method
func textFieldDidBeginEditing(_ textField: UITextField) {
    textField.resignFirstResponder()
    let secondVC = SecondVC()
    
    // Add [weak self] here to break the retain cycle
    secondVC.completion = { [weak self] returnedData in
        self?.textField.text = returnedData
    }
    
    navigationController?.pushViewController(secondVC, animated: true)
}

Also, add a deinit method to both view controllers to verify they're being deallocated. If deinit doesn't print for either, you've got a retain cycle to fix:

// Add this to FirstVC and SecondVC
deinit {
    print("\(self) was deallocated")
}

2. Stop Repeating Target-Action Bindings

If you're adding the button's tap handler programmatically (not in Storyboards/XIBs), you might be binding the action multiple times (e.g., in viewWillAppear instead of viewDidLoad). This causes the button to fire multiple or broken callbacks on the second run.

Solution:

  • Bind the button action only once in viewDidLoad:
// In SecondVC
override func viewDidLoad() {
    super.viewDidLoad()
    // This runs once per SecondVC instance
    confirmButton.addTarget(self, action: #selector(confirmTapped), for: .touchUpInside)
}

@objc private func confirmTapped() {
    completion?("Your returned data")
    navigationController?.popViewController(animated: true)
}
  • If you must bind in a repeated lifecycle method, clear old bindings first:
confirmButton.removeTarget(nil, action: nil, for: .allEvents)
confirmButton.addTarget(self, action: #selector(confirmTapped), for: .touchUpInside)

3. Reset Delegate References Properly

If you're using a delegate pattern instead of closures, make sure:

  • The delegate is marked as weak (since delegates should never retain their parent view controller)
  • You set the delegate every time you create a new SecondVC instance

Solution:

// In SecondVC
protocol SecondVCDelegate: AnyObject {
    func didReturnData(_ data: String)
}

class SecondVC: UIViewController {
    // Mark delegate as weak to avoid retain cycles
    weak var delegate: SecondVCDelegate?
    
    @objc private func confirmTapped() {
        delegate?.didReturnData("Your returned data")
        navigationController?.popViewController(animated: true)
    }
}

// In FirstVC (conform to the delegate)
extension FirstVC: SecondVCDelegate {
    func didReturnData(_ data: String) {
        textField.text = data
    }
}

// When opening SecondVC
func textFieldDidBeginEditing(_ textField: UITextField) {
    textField.resignFirstResponder()
    let secondVC = SecondVC()
    // Set delegate every time (don't reuse old instances!)
    secondVC.delegate = self
    navigationController?.pushViewController(secondVC, animated: true)
}

4. Fix Navigation Stack Issues

Sometimes the problem isn't with the button itself—it's with how you're navigating back. If you're not properly popping/dismissing SecondVC, you might end up with multiple instances in the navigation stack, leading to broken callbacks.

Solution:

  • Always use the standard navigation methods to return:
    • If pushed: navigationController?.popViewController(animated: true)
    • If presented: dismiss(animated: true)
  • Never reuse old SecondVC instances—always create a new one when the text field begins editing.

Quick Debugging Tip

Add print statements in your button tap handler and completion/delegate methods. If the button tap doesn't print on the second run, your button's action isn't bound correctly. If it prints but the data doesn't show up, your callback reference is broken.

内容的提问来源于stack exchange,提问作者Ahtazaz khan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 03:30:52