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)
- If pushed:
- 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

