0

I have a tabBar with a tab that contains a NavVC that has a root as a ParentVC. The ParentVC has a segmentedControl that manages two childVCs, RedVC and BlueVC. Both the RedVC and BlueVC contain a button to push on a YellowVC.

The issue is when the YellowVC gets pushed on, and in it's viewDidLoad I check to see the view controllers on the stack, the two controllers that appear are the ParentVC and the YellowVC, there is no mention of either The RedVC (if it pushes it on) or the BlueVC (if it pushes it on).

for controller in navigationController!.viewControllers {

    print(controller.description) // will only print ParentVC and YellowVC
}

I understand that since the tabBar has a navVC as it's tab and it's root is the ParentVC then that's the root of the push but I need to know which one of either the RedVC or the BlueVC triggered it when the YellowVC gets pushed on.

I can use some class properties in the YellowVC but I want to see if there's another way via the navigationController:

var pushedFromRedVC = false // I'd prefer not to use these if I don't have to
var pushedFromBlueVC = false

How can I get a reference to the RedVC or BlueVC when either of them push on the YellowVC?

class MyTabBarController: UITabBarController {

    override func viewDidLoad() {
        super.viewDidLoad()

        let parentVC = ParentVC()
        let navVC = UINavigationController(rootViewController: parentVC)
        navVC.tabBarItem = UITabBarItem(title: "Parent", image: nil), tag: 0)

        viewControllers = [navVC]
    }
}

class ParentVC: UIViewController {

    var segmentedControl: UISegmentedControl! // switching segments will show either the redVC or the blueVC
    let redVC = RedController()
    let blueVC = BlueController()

    override func viewDidLoad() {
        super.viewDidLoad()

        addChildViewController(redVC)
        view.addSubview(redVC.view)
        redVC.didMove(toParentViewController: self)

        addChildViewController(blueVC)
        view.addSubview(blueVC.view)
        blueVC.didMove(toParentViewController: self)
    }
}

class RedVC: UIViewController {

    @IBAction func pushYellowVC(sender: UIButton) {

        let yellowVC = YellowVC()
        yellowVC.pushedFromRedVC = true // I'd rather not rely on this
        navigationController?.pushViewController(yellowVC, animated: true)
    }
}

class BlueVC: UIViewController {

    @IBAction func pushYellowVC(sender: UIButton) {

        let yellowVC = YellowVC()
        yellowVC.pushedFromBlueVC = true  // I'd rather not rely on this
        navigationController?.pushViewController(yellowVC, animated: true)
    }
}

class YellowVC: UIViewController {

    var pushedFromRedVC = false // only sample, I'd rather not use these if I don't have to
    var pushedFromBlueVC = false

    override func viewDidLoad() {
        super.viewDidLoad()


        for controller in navigationController!.viewControllers {
            // even though the push is triggered from either the RedVC or BlueVC it will only print ParentVC and YellowVC
            print(controller.description)
        }
    }
}
Lance Samaria
  • 17,576
  • 18
  • 108
  • 256

1 Answers1

0

Since RedVC and BlueVC are contained in ParentVC you won't find any reference to them in the UINavigationController stack.

An alternative to using the two booleans, is to use a sourceVC property:

class YellowVC: UIViewController {

    var sourceVC: UIViewController?

    override func viewDidLoad() {
        super.viewDidLoad()

        if self.sourceVC is BlueVC {
           print("We came from Blue")
        } else if self.sourceVC is RedVC {
           print("We came from Red")
        } else {
           print("We came from somewhere else"
        }
    }
}


class RedVC: UIViewController {

    @IBAction func pushYellowVC(sender: UIButton) {

        let yellowVC = YellowVC()
        yellowVC.sourceVC = self 
        navigationController?.pushViewController(yellowVC, animated: true)
    }
}

class BlueVC: UIViewController {

    @IBAction func pushYellowVC(sender: UIButton) {

        let yellowVC = YellowVC()
        yellowVC.sourceVC = self  
        navigationController?.pushViewController(yellowVC, animated: true)
    }
}

You may need to think about whether YellowVC needs to invoke some method on Red/BlueVC or just needs to know some state that is implied by the Red/Blue source.

If it is the latter then RedVC and BlueVC should probably use a delegation pattern to let ParentVC know that it should push YellowVC and set the appropriate state properties based on the source of the delegation call.

You could also consider putting the state into your model that is passed down to the VCs rather than discrete properties on the VCs themselves.

Paulw11
  • 108,386
  • 14
  • 159
  • 186
  • thanks. It creates sort of the same dilemma. This is a contrived example but in reality I'm pushing more vcs down the stack and eventually I'm going to need to know wether the red or blue pushed it on. I didn't want to add all the Bool properties to all the additional vcs and thought there was possibly a way through the nav stack. Doesn't look like it's possible other then doing it. Your idea should work. Thanks I'll think it over. – Lance Samaria Nov 04 '18 at 10:14
  • You need to think about whether `YellowVC` needs to invoke some method on `Red/BlueVC` or just needs to know some state that is implied by the Red/Blue source. If the latter then `RedVC` and `BlueVC` should probably use a delegation pattern to let `ParentVC` know that it should push `YellowVC` and set the appropriate state properties based on the source of the delegation call. You could also consider putting the state into your model that is passed down to the VCs rather than discrete properties on the VCs themselves – Paulw11 Nov 04 '18 at 10:21
  • Delegation pattern actually might be a good alternative. That's a good idea right there. That didn't cross my mind. Thanks! – Lance Samaria Nov 04 '18 at 10:25