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

视图控制器导航与状态保持的核心技术问题

Hey Jacob, great question—this is a super common gotcha when working with navigation controllers and segues. Since segues create a new instance of the destination view controller every time you trigger them, your button color changes don’t stick by default. Let’s walk through three practical solutions depending on your needs:

Solution 1: Reuse a Single Instance of VC B

If you want to preserve the exact state of VC B (not just the button color, but any other user interactions or data), the simplest approach is to keep a reference to the B instance in VC A and reuse it instead of creating a new one each time.

  • Step 1: Add a property to VC A to hold the B instance:

    class AViewController: UIViewController {
        private var vcB: BViewController?
        // ... rest of your code
    }
    
  • Step 2: Replace the segue with a manual push action (you can delete the segue from your storyboard and add an IBAction to your "Go to B" button):

    @IBAction func navigateToBTapped(_ sender: UIButton) {
        if let existingVCB = vcB {
            // Push the already-existing instance
            navigationController?.pushViewController(existingVCB, animated: true)
        } else {
            // First time: instantiate from storyboard and save the reference
            guard let newVCB = storyboard?.instantiateViewController(withIdentifier: "BViewController") as? BViewController else { return }
            vcB = newVCB
            navigationController?.pushViewController(newVCB, animated: true)
        }
    }
    

This way, every time you navigate to B, you’re using the same instance—so all your button color changes (and any other state) will be preserved. Just note: this keeps VC B in memory as long as VC A exists, so it’s best for lightweight view controllers.

Solution 2: Persist State to an External Store

If you don’t want to keep VC B in memory, or need the state to persist even if the app restarts, save the button color to a shared storage (like a view model or UserDefaults), then restore it when VC B loads.

Example with a View Model (cleaner than UserDefaults for app state):

  1. Create a shared view model to hold the state:

    class BViewModel {
        static let shared = BViewModel()
        var buttonBackgroundColor: UIColor = .systemBlue // Default color
    }
    
  2. In VC B, update the view model when the button is tapped:

    @IBAction func changeColorTapped(_ sender: UIButton) {
        let newColor = UIColor.systemRed // Your desired color
        sender.backgroundColor = newColor
        BViewModel.shared.buttonBackgroundColor = newColor
    }
    
  3. Restore the color when VC B appears:

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        changeColorButton.backgroundColor = BViewModel.shared.buttonBackgroundColor
    }
    

This works even if you use segues (since each new B instance will pull the latest state from the view model).

Solution 3: Pass State Back to A, Then Forward to New B

If you prefer to create a new instance of B every time, but still want to carry over the button color, pass the state from B back to A during the unwind, then forward it to the new B instance when you segue again.

  • Step 1: Add an unwind action to VC A to capture the state from B:

    class AViewController: UIViewController {
        private var savedButtonColor: UIColor?
    
        @IBAction func unwindToA(_ segue: UIStoryboardSegue) {
            if let sourceVC = segue.source as? BViewController {
                savedButtonColor = sourceVC.changeColorButton.backgroundColor
            }
        }
        // ...
    }
    

    (Don’t forget to connect the unwind segue in your storyboard: drag from VC B’s exit icon to the "Unwind to A" action.)

  • Step 2: Pass the saved color to the new B instance in VC A’s prepare(for:):

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "ToVCB", let destinationVC = segue.destination as? BViewController {
            destinationVC.preferredButtonColor = savedButtonColor
        }
    }
    
  • Step 3: Add a property to VC B and apply the color when it loads:

    class BViewController: UIViewController {
        var preferredButtonColor: UIColor?
    
        override func viewWillAppear(_ animated: Bool) {
            super.viewWillAppear(animated)
            if let color = preferredButtonColor {
                changeColorButton.backgroundColor = color
            }
        }
        // ...
    }
    

Which one should you choose?

  • Go with Solution 1 if you need to preserve the entire state of VC B (e.g., text inputs, scroll position, etc.).
  • Choose Solution 2 if you want persistent state (even across app restarts) or don’t want to hold onto VC B’s instance.
  • Use Solution 3 if you prefer fresh instances of B but need to carry over specific state values.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 09:11:27