[ios] How to tell if UIViewController's view is visible

I have a tab bar application, with many views. Is there a way to know if a particular UIViewController is currently visible from within the UIViewController? (looking for a property)

This question is related to ios uiview uiviewcontroller uiwindow

The answer is


if you're utilizing a UINavigationController and also want to handle modal views, the following is what i use:

#import <objc/runtime.h>

UIViewController* topMostController = self.navigationController.visibleViewController;
if([[NSString stringWithFormat:@"%s", class_getName([topMostController class])] isEqualToString:@"NAME_OF_CONTROLLER_YOURE_CHECKING_IN"]) {
    //is topmost visible view controller
}

You want to use the UITabBarController's selectedViewController property. All view controllers attached to a tab bar controller have a tabBarController property set, so you can, from within any of the view controllers' code:

if([[[self tabBarController] selectedViewController] isEqual:self]){
     //we're in the active controller
}else{
     //we are not
}

For over-full-screen or over-context modal presentation, "is visible" could mean it is on top of the view controller stack or just visible but covered by another view controller.

To check if the view controller "is the top view controller" is quite different from "is visible", you should check the view controller's navigation controller's view controller stack.

I wrote a piece of code to solve this problem:

extension UIViewController {
    public var isVisible: Bool {
        if isViewLoaded {
            return view.window != nil
        }
        return false
    }

    public var isTopViewController: Bool {
        if self.navigationController != nil {
            return self.navigationController?.visibleViewController === self
        } else if self.tabBarController != nil {
            return self.tabBarController?.selectedViewController == self && self.presentedViewController == nil
        } else {
            return self.presentedViewController == nil && self.isVisible
        }
    }
}

XCode 6.4, for iOS 8.4, ARC enabled

Obviously lots of ways of doing it. The one that has worked for me is the following...

@property(nonatomic, readonly, getter=isKeyWindow) BOOL keyWindow

This can be used in any view controller in the following way,

[self.view.window isKeyWindow]

If you call this property in -(void)viewDidLoad you get 0, then if you call this after -(void)viewDidAppear:(BOOL)animated you get 1.

Hope this helps someone. Thanks! Cheers.


There are a couple of issues with the above solutions. If you are using, for example, a UISplitViewController, the master view will always return true for

if(viewController.isViewLoaded && viewController.view.window) {
    //Always true for master view in split view controller
}

Instead, take this simple approach which seems to work well in most, if not all cases:

- (void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:animated];

    //We are now invisible
    self.visible = false;
}

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];

    //We are now visible
    self.visible = true;
}

If you are using a navigation controller and just want to know if you are in the active and topmost controller, then use:

if navigationController?.topViewController == self {
    // Do something
}

This answer is based on @mattdipasquale's comment.

If you have a more complicated scenario, see the other answers above.


I use this small extension in Swift 5, which keeps it simple and easy to check for any object that is member of UIView.

extension UIView {
    var isVisible: Bool {
        guard let _ = self.window else {
            return false
        }
        return true
    }
}

Then, I just use it as a simple if statement check...

if myView.isVisible {
    // do something
}

I hope it helps! :)


Here's @progrmr's solution as a UIViewController category:

// UIViewController+Additions.h

@interface UIViewController (Additions)

- (BOOL)isVisible;

@end


// UIViewController+Additions.m

#import "UIViewController+Additions.h"

@implementation UIViewController (Additions)

- (BOOL)isVisible {
    return [self isViewLoaded] && self.view.window;
}

@end

The approach that I used for a modal presented view controller was to check the class of the presented controller. If the presented view controller was ViewController2 then I would execute some code.

UIViewController *vc = [self presentedViewController];

if ([vc isKindOfClass:[ViewController2 class]]) {
    NSLog(@"this is VC2");
}

For those of you looking for a Swift 2.2 version of the answer:

if self.isViewLoaded() && (self.view.window != nil) {
     // viewController is visible
}

and Swift 3:

if self.isViewLoaded && (self.view.window != nil) {
         // viewController is visible
}

I made a swift extension based on @progrmr's answer.

It allows you to easily check if a UIViewController is on screen like so:

if someViewController.isOnScreen {
    // Do stuff here
}

The extension:

//
//  UIViewControllerExtension.swift
//

import UIKit

extension UIViewController{
    var isOnScreen: Bool{
        return self.isViewLoaded() && view.window != nil
    }
}

For my purposes, in the context of a container view controller, I've found that

- (BOOL)isVisible {
    return (self.isViewLoaded && self.view.window && self.parentViewController != nil);
}

works well.


I found those function in UIViewController.h.

/*
  These four methods can be used in a view controller's appearance callbacks to determine if it is being
  presented, dismissed, or added or removed as a child view controller. For example, a view controller can
  check if it is disappearing because it was dismissed or popped by asking itself in its viewWillDisappear:
  method by checking the expression ([self isBeingDismissed] || [self isMovingFromParentViewController]).
*/

- (BOOL)isBeingPresented NS_AVAILABLE_IOS(5_0);
- (BOOL)isBeingDismissed NS_AVAILABLE_IOS(5_0);

- (BOOL)isMovingToParentViewController NS_AVAILABLE_IOS(5_0);
- (BOOL)isMovingFromParentViewController NS_AVAILABLE_IOS(5_0);

Maybe the above functions can detect the ViewController is appeared or not.


I needed this to check if the view controller is the current viewed controller, I did it via checking if there's any presented view controller or pushed through the navigator, I'm posting it in case anyone needed such a solution:

if presentedViewController != nil || navigationController?.topViewController != self {
      //Viewcontroller isn't viewed
}else{
     // Now your viewcontroller is being viewed 
}

Good point that view is appeared if it's already in window hierarchy stack. thus we can extend our classes for this functionality.

extension UIViewController {
  var isViewAppeared: Bool { viewIfLoaded?.isAppeared == true }
}

extension UIView {
  var isAppeared: Bool { window != nil }
}

you can check it by window property

if(viewController.view.window){

// view visible

}else{

// no visible

}

Examples related to ios

Adding a UISegmentedControl to UITableView Crop image to specified size and picture location Undefined Symbols error when integrating Apptentive iOS SDK via Cocoapods Keep placeholder text in UITextField on input in IOS Accessing AppDelegate from framework? Autoresize View When SubViews are Added Warp \ bend effect on a UIView? Speech input for visually impaired users without the need to tap the screen make UITableViewCell selectable only while editing Xcode 12, building for iOS Simulator, but linking in object file built for iOS, for architecture arm64

Examples related to uiview

How can I mimic the bottom sheet from the Maps app? UIView touch event in controller Swift addsubview and remove it Swift UIView background color opacity How do I change UIView Size? How to add constraints programmatically using Swift Load a UIView from nib in Swift Remove all constraints affecting a UIView How do I write a custom init for a UIView subclass in Swift? How to use UIVisualEffectView to Blur Image?

Examples related to uiviewcontroller

How to set Status Bar Style in Swift 3 UIView touch event in controller How to lock orientation of one view controller to portrait mode only in Swift Programmatically navigate to another view controller/scene Adding a view controller as a subview in another view controller Changing the Status Bar Color for specific ViewControllers using Swift in iOS8 Get top most UIViewController Instantiate and Present a viewController in Swift How to check if a view controller is presented modally or pushed on a navigation stack? Add a UIView above all, even the navigation bar

Examples related to uiwindow

Getting reference to the top-most view/window in iOS application How to tell if UIViewController's view is visible iPhone - Get Position of UIView within entire UIWindow