85

As far as I know, this would work in Objective-C:

self.window.rootViewController.class == myViewController

How can I check if the current view controller is a specific one?

user83039
  • 3,047
  • 5
  • 19
  • 31
  • Are you trying to determine if it's an instance of a particular class, or a specific instance? – mc01 Dec 31 '14 at 03:53

18 Answers18

98

To check the class in Swift, use "is" (as explained under "checking Type" in the chapter called Type Casting in the Swift Programming Guide)

if self.window.rootViewController is MyViewController {
    //do something if it's an instance of that class
}
mc01
  • 3,750
  • 19
  • 24
  • 9
    The variable `self.window` does not exist – user83039 Dec 31 '14 at 03:58
  • @user83039 What is `self` in this case then? Where are you putting the code? self.window and rootViewController are in AppDelegate. Need more info. – mc01 Dec 31 '14 at 04:23
  • I'm inside of a view controller. – user83039 Dec 31 '14 at 04:29
  • 1
    That's the problem then - viewControllers don't have a window, and any code you put there will only tell you about itself, which isn't helpful. See: http://stackoverflow.com/questions/20485585/get-current-view-controller-from-the-app-delegate-modal-is-possible AND http://stackoverflow.com/questions/11637709/get-the-current-displaying-uiviewcontroller-on-the-screen-in-appdelegate-m – mc01 Dec 31 '14 at 04:34
50

Updated for swift3 compiler throwing a fit around ! and ?

if let wd = UIApplication.shared.delegate?.window {
        var vc = wd!.rootViewController
        if(vc is UINavigationController){
            vc = (vc as! UINavigationController).visibleViewController

        }

        if(vc is LogInViewController){
            //your code
        }
    }
Alex Stone
  • 46,408
  • 55
  • 231
  • 407
Nhut Duong
  • 612
  • 4
  • 5
32

You can easily iterate over your view controllers if you are using a navigation controller. And then you can check for the particular instance as:
Swift 5

 if let viewControllers = navigationController?.viewControllers {
            for viewController in viewControllers {
                if viewController.isKind(of: LoginViewController.self) {
                    
                }
            }
        }
IOS Singh
  • 617
  • 6
  • 15
Kiran Thapa
  • 1,230
  • 2
  • 13
  • 28
  • 1
    I don't have an object, the current window is supposed to be the object. – user83039 Jan 01 '15 at 02:26
  • 1
    Use self.isKindOfClass then – Kiran Thapa Jan 01 '15 at 04:03
  • 1
    self is not necessarily what is being shown if I'm using that function from another class... – user83039 Jan 01 '15 at 04:11
  • I'm using both actually. The navigation controllers are inside the tab bar controller. – user83039 Jan 01 '15 at 06:00
  • What if I put this inside of a `struct` inside of the class? – user83039 Jan 02 '15 at 00:32
  • Sure, you can define this inside a method of struct. – Kiran Thapa Jan 02 '15 at 01:53
  • Interesting, because when I have it there, it doesn't throw errors but when I move it over, it says `'ThisViewController.Type' does not have a member named 'navigationController'` but before I moved it into the struct, it did. – user83039 Jan 02 '15 at 03:24
  • I was using protocols and the delegate pattern to call common methods in one view controller class from other view controller classes and encountering the error `fatal error: unexpectedly found nil while unwrapping an Optional value` because those methods included statements that used storyboard outlets only attached to the specific view controller associated with the class containing the methods but not the other classes (i.e. `self.myButton.hidden = true` where myButton is an IBOutlet connected to just one view controller). I used your template as a wrapper for these statements. Thank you – Luke Schoen Oct 28 '15 at 21:13
13

Try this

if self is MyViewController {        

}
boraseoksoon
  • 2,164
  • 1
  • 20
  • 25
  • 1
    self is not necessarily what is being shown if I'm using a function from another class... – user83039 Jan 01 '15 at 02:01
  • Thanks, this helped. This is particularly useful for checking the currently presenting viewController. I was able to tell whether the controller was a UIAlertController to prevent multiple presentations. – 6rchid Aug 19 '20 at 02:31
13

I had to find the current viewController in AppDelegate. I used this

//at top of class
var window:UIWindow?

// inside my method/function
if let viewControllers = window?.rootViewController?.childViewControllers {
    for viewController in viewControllers {
        if viewController.isKindOfClass(MyViewControllerClass) {
            println("Found it!!!")
            }
        }
    }
Ivan Reyes
  • 131
  • 2
8

Swift 3

Not sure about you guys, but I'm having a hard time with this one. I did something like this:

if let window = UIApplication.shared.delegate?.window {
    if var viewController = window?.rootViewController {
        // handle navigation controllers
        if(viewController is UINavigationController){
            viewController = (viewController as! UINavigationController).visibleViewController!
        }
        print(viewController)
    }
}

I kept getting the initial view controller of my app. For some reason it wanted to stay the root view controller no matter what. So I just made a global string type variable currentViewController and set its value myself in each viewDidLoad(). All I needed was to tell which screen I was on & this works perfectly for me.

Trev14
  • 3,626
  • 2
  • 31
  • 40
7

To go off of Thapa's answer, you need to cast to the viewcontroller class before using...

   if let wd = self.view.window {
        var vc = wd.rootViewController!
        if(vc is UINavigationController){
            vc = (vc as! UINavigationController).visibleViewController
        }
        if(vc is customViewController){
            var viewController : customViewController = vc as! customViewController
KorinW
  • 279
  • 4
  • 10
7

Swift 4, Swift 5

let viewController = UIApplication.shared.keyWindow?.rootViewController
if viewController is MyViewController {

}
Pengguna
  • 4,636
  • 1
  • 27
  • 32
1

For types you can use is and if it is your own viewcontroller class then you need to use isKindOfClass like:

let vcOnTop = self.embeddedNav.viewControllers[self.embeddedNav.viewControllers.count-1]
            if vcOnTop.isKindOfClass(VcShowDirections){
                return
            }
1

Swift 3 | Check if a view controller is the root from within itself.

You can access window from within a view controller, you just need to use self.view.window.

Context: I need to update the position of a view and trigger an animation when the device is rotated. I only want to do this if the view controller is active.

class MyViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()

        NotificationCenter.default.addObserver(
            self, 
            selector: #selector(deviceDidRotate), 
            name: .UIApplicationDidChangeStatusBarOrientation, 
            object: nil
        )
    }

    func deviceDidRotate() {
        guard let window = self.view.window else { return }

        // check if self is root view controller
        if window.rootViewController == self {
            print("vc is self")
        }

        // check if root view controller is instance of MyViewController
        if window.rootViewController is MyViewController {
            print("vc is MyViewController")
        }
    }
}

If you rotate your device while MyViewController is active, you will see the above lines print to the console. If MyViewController is not active, you will not see them.

If you're curious why I'm using UIDeviceOrientationDidChange instead of .UIDeviceOrientationDidChange, look at this answer.

Community
  • 1
  • 1
Derek Soike
  • 11,238
  • 3
  • 79
  • 74
1
let viewControllers = navController?.viewControllers
        for aViewController in viewControllers! {

            if aViewController .isKind(of: (MyClass?.classForCoder)!) {
                _ = navController?.popToViewController(aViewController, animated: true)
            }
        }
Hemanshu Liya
  • 611
  • 6
  • 10
1

Check that way that worked better for me What is .self

if ((self.window.rootViewController?.isKind(of: WebViewController.self))!)
{
  //code
}
ΩlostA
  • 2,501
  • 5
  • 27
  • 63
1

After implementing and try is current viewController is open I find 100% solution

for example when receiving a new notification

here the implement using 'userNotificationCenter'

func userNotificationCenter(_ center: UNUserNotificationCenter,
                            willPresent notification: UNNotification,
                            withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void) {
    let userInfo = notification.request.content.userInfo
    
    // Change this to your preferred presentation option
    Messaging.messaging().appDidReceiveMessage(userInfo)
    
    let keyWindow = UIApplication.shared.connectedScenes
        .map({$0 as? UIWindowScene})
        .compactMap({$0})
        .first?.windows
        .filter({$0.isKeyWindow}).first
    
    guard let window = keyWindow else { return }
    
    if window.rootViewController?.children.last is MyViewController{
        print("Chat")
        completionHandler([])
    }else{
        print("Not not not Chat")
        completionHandler([.alert, .badge, .sound])
    }
 }

and simply to check try this

let keyWindow = UIApplication.shared.connectedScenes
        .map({$0 as? UIWindowScene})
        .compactMap({$0})
        .first?.windows
        .filter({$0.isKeyWindow}).first
    
    guard let window = keyWindow else { return }
    
    if window.rootViewController?.children.last is MyViewController{
        print("Yes Its current ViewController")
    }else{
        print("Not it's not Current ViewController")
    }
Ahmad Mustafa
  • 521
  • 1
  • 3
  • 12
1

Swift 5 and iOS 15

if self.navigationController?.presentedViewController != nil && 
        self.navigationController?.presentedViewController is ChatViewController {
            return
    }
logeshpalani31
  • 1,416
  • 12
  • 33
0
if let index = self.navigationController?.viewControllers.index(where: { $0 is MyViewController }) {
            let vc = self.navigationController?.viewControllers[vcIndex] as! MyViewController
            self.navigationController?.popToViewController(vc, animated: true)
        } else {
            self.navigationController?.popToRootViewController(animated: true)
        }
0

My suggestion is a variation on Kiran's answer above. I used this in a project.

Swift 5

// convenience property API on my class object to provide access to the my WindowController (MyController).
var myXWindowController: MyController? {

    var myWC: MyController?                
    for viewController in self.windowControllers {
        if ((viewController as? MyController) != nil) {
            myWC = viewController as? MyController
            break
        }
    }

    return myWC
}

// example of use
guard let myController = myXWindowController else {
    reportAssertionFailure("Failed to get MyXController from WindowController.")
    return
}  
Douglas Frari
  • 4,167
  • 2
  • 22
  • 23
0
 var top = window?.rootViewController
            while ((top?.presentedViewController) != nil) {
                top = top?.presentedViewController
            }
            
            if !(type(of: top!) === CallingVC.self) {
                top?.performSegue(withIdentifier: "CallingVC", sender: call)
            }
0

I chose to create my own enum to keep track of which view controller I was on:

enum currentViewController{
   case publicVC
   case homeVC
   case friendsVC
}

Then in each of your viewWillAppears change a global variable to equal the respective enum.

David
  • 769
  • 1
  • 6
  • 28