22

I have two view controllers. I have navigated from one view to another view by press the button to using below code.

 *let secondViewController = self.storyboard!.instantiateViewControllerWithIdentifier("NotificationController") as! NotificationController

self.navigationController!.pushViewController(secondViewController, animated: true)*

For the back, I am using bar button on bar button click for back using below code.

 self.navigationController?.popViewControllerAnimated(true)

So my problem is if I am going from one view to another view continuously then it added in a stack. I want to only show another view when it is already added to the stack to stop adding it.It only adds one time.

Gaurav Gupta
  • 593
  • 2
  • 10
  • 31

11 Answers11

31

To check whether the navigation stack contains a particular type of view controller, you can use:

if let viewControllers = self.navigationController?.viewControllers
{
    if viewControllers.contains(where: {
        return $0 is YourViewController
    })
    {
        //Write your code here
    }
}

To remove a particular controller from navigation stack, you need to make changes to the navigation stack.

Example:

    if var viewControllers = self.navigationController?.viewControllers
    {
        for controller in viewControllers
        {
            if controller is UIViewController
            {
                viewControllers.removeElement(controller)
                self.navigationController?.viewControllers = viewControllers
            }
        }
    }
PGDev
  • 23,751
  • 6
  • 34
  • 88
  • There is no 'removeElement()' method on Array. But you can perform the same thing by filtering the viewControllers property. Please see my answer for an example, and an elaboration of your answer. Cheers. – Womble Jun 03 '18 at 02:06
19

For swift 4 you can use

 if let viewControllers = self.navigationController?.viewControllers {
       for vc in viewControllers {
            if vc.isKind(of: YourViewController.classForCoder()) {
                 print("It is in stack")
                 //Your Process
            }
       }
 }
Michal Šrůtek
  • 1,647
  • 16
  • 17
vp2698
  • 1,783
  • 26
  • 28
15

Elaborating on PGDev's answer, for Swift 4.1

How to remove a specific UIViewController subclass from the UINavigationController stack:

/// Given 'nc' is a valid UINavigationController instance,
/// removes all instances of MyViewController from the stack

nc.viewControllers = nc.viewControllers.filter { !($0 is MyViewController) }

Putting it an an extension:

extension UINavigationController
{
    /// Given the kind of a (UIViewController subclass),
    /// removes any matching instances from self's
    /// viewControllers array.

    func removeAnyViewControllers(ofKind kind: AnyClass)
    {
        self.viewControllers = self.viewControllers.filter { !$0.isKind(of: kind)}
    }

    /// Given the kind of a (UIViewController subclass),
    /// returns true if self's viewControllers array contains at
    /// least one matching instance.

    func containsViewController(ofKind kind: AnyClass) -> Bool
    {
        return self.viewControllers.contains(where: { $0.isKind(of: kind) })
    }
}

Usage:

guard let nc = self.navigationController else { return }

let exists = nc.containsViewController(ofKind: MyViewController.self)

nc.removeAnyViewControllers(ofKind: MyViewController.self)

BTW, if anyone knows how to constrain 'kind' to subclasses of UIViewController, please yell out.

Womble
  • 4,607
  • 2
  • 31
  • 45
  • 1
    func containsViewController(ofKind kind: UIViewController.Type) -> Bool { return self.viewControllers.contains(where: { $0.isKind(of: kind) }) } – appleitung Jul 30 '18 at 15:24
5

Here is the code to check it.

if let viewControllers = navigationController?.viewControllers {
    for viewController in viewControllers {
        // some process
        if viewController.isKindOfClass(ViewControllerClassName) {
            println("yes it is")
        }
    } 
}
Sivajee Battina
  • 4,124
  • 2
  • 22
  • 45
4
extension UINavigationController {
    public func hasViewController(ofKind kind: AnyClass) -> UIViewController? {
        return self.viewControllers.first(where: {$0.isKind(of: kind)})
    }
}

USE

self.navigationController.hasViewController(ofKind: #ViewControllerName#.self)
GameLoading
  • 6,688
  • 2
  • 33
  • 57
2

Here we go.

This line will give you a array of UIViewControllers

self.navigationController?.viewControllers

Now what you have to do is check your viewControllerObject does exist or not?

By writing this line

if viewController.isKindOfClass(YourController){
}

and here is a complete code.

if let viewControllers = self.navigationController?.viewControllers {
            for viewController in viewControllers {

                if viewController.isKindOfClass(YourController) {
                    print("Your controller exist")
                }
       } 
}

When you write below line while going back to your 'ViewControllerA' it will remove a ViewControllerB from navigation stack.

self.navigationController?.popViewControllerAnimated(true)

It is just similar pop operation which we are doing with stack and navigationcontroller is a stack.

Let me know if you have any confusions.

Anil Kukadeja
  • 1,348
  • 1
  • 14
  • 27
0

You can check with below code

Objective - C

NSArray * controllers = [self.navigationController viewControllers];

    for (int i = 0; i < [controllers count]; i++){

        UIViewController * controllerTest = [controllers objectAtIndex:i];

        if([controllerTest isKindOfClass:[YourController class]]){
            NSLog(@"Class is available");
        }

    }

Swift 3.0

if let viewControllers = self.navigationController?.viewControllers {
            for viewController in viewControllers {
                // some process
                if viewController.isKindOfClass(YourController) {
                    print("Class is available")
                }
            } 
        }
Abhishek Sharma
  • 3,283
  • 1
  • 13
  • 22
0

Swift 5(Working tested). Better way to check whether the view controller is stacked in navigation or not is by simply asking for the view controller's accessibility.See example below.I use this snippet to go back to previous view controller.

    if self.navigationController?.accessibilityActivate() != nil {
        self.navigationController?.popViewController(animated: true)
    } else {
        self.dismiss(animated: true, completion: nil)
    }
Nishad Arora
  • 304
  • 1
  • 5
  • 12
0

Here's another solotion:

    guard let controllersInStack = navigationController?.viewControllers else { return }
    if let yourViewController = controllersInStack.first(where: { $0 is YourViewController }) {
        // Do what you want with yourViewController
    }
Faipdeoiad
  • 102
  • 2
  • 3
0

All you need is to check with nibName of the viewController and you have your result

this code below will make sure you don't add one viewController again in navigatoinController,

    var VC = YourViewController
    var objVC = (storyboard.instantiateViewController(withIdentifier: "YourViewController"))
    
if navigationController.viewControllers.contains(where: { (VC) -> Bool in
            return objVC.nibName == VC.nibName
        }){
            for (i,controller) in navigationController.viewControllers.enumerated()
            {
                if controller.isKind(of: VC){
                    navigationController.viewControllers.remove(at: i)
                    navigationController.pushViewController(objVC, animated: false)
                }
            }
        }else{navigationController.pushViewController(objVC, animated: false)}

and If you just want to check if the viewController is in NaviagtionController then try this:

var checkForView = navigationController.viewControllers.contains(where: { (VC) -> Bool in
            return objVC.nibName == VC.nibName
        })
kishan savani
  • 194
  • 1
  • 8
0
extension UINavigationController {

    func firstViewController<T: UIViewController>(ofClass: T.Type) -> UIViewController? {
        return self.viewControllers.compactMap({ $0 as? T }).first
    }
}


// EXAMPLE:

if let vc = navController.firstViewController(ofClass: MyViewController.self)
{
    // do stuff
}
Kirby Todd
  • 11,254
  • 3
  • 32
  • 60