22

How do I check if an UIViewController is currently being displayed?

My UIViewControllers are listening for NSNotifications - even if when they are not displayed (ie not shown). So I could have 10 UIViewController in the background observing NSNotifications from NSNotificationCenter. When an NSNotification is posted and received by the UIViewController, I'd like to find out if it is currently being shown. If it is not, I will just set a boolean so that it will processed when the View is presented. If it currently being display, I will do more things like update tables immediately, and so forth...

iDev
  • 23,310
  • 7
  • 60
  • 85
ikevin8me
  • 4,253
  • 5
  • 44
  • 84
  • How are you presenting view controller's view ? – Tomasz Dubik Oct 09 '12 at 20:43
  • @tdubik: the traditional way, like pushViewController. I'm not using StoryBoard or segues. – ikevin8me Oct 09 '12 at 20:46
  • In such case you can check `topViewController` from `UINavigationController` class. Or if you want to process more then one controller enumerate `viewControllers` array. – Tomasz Dubik Oct 09 '12 at 20:49
  • Answers to your question aside, why don't you just ditch the `NSNotifications`, create a `BOOL` called `isVisible` and set the value when `viewDidAppear` and `viewDidDisappear` are called? Then in your `viewWillAppear` (or wherever) you can just check your `BOOL` and loose a whole lot of complexity. – DBD Oct 10 '12 at 12:56

8 Answers8

21

You need to check if your viewcontroller is on top of the stack of navigationcontroller's viewcontroller array. A sample code is,

if (self.navigationController.topViewController == self) {
    //the view is currently displayed
}

You can use this inside the viewWillAppear method to check whether the current view is visible.

iDev
  • 23,310
  • 7
  • 60
  • 85
  • 2
    @DBD's answer is a more generic one and since the question title is not that specific, will be more helpful to future readers. – Zedenem Mar 16 '17 at 12:32
  • What about a pageviewcontroller? What is the "self.nav" equivalent? Like.. self.page..? –  Sep 24 '20 at 01:38
12

Check to see if it's attached to the window. If it's not nil it's in hierarchy which is attached to the screen (of course it could be off the bounds of the screen, covered by some other view or have the hidden flag set)

if (myViewController.view.window) {
  // I'm attached to the window
} else {
  // not attached to the window
}
DBD
  • 23,075
  • 12
  • 60
  • 84
  • 2
    Close, but you should check whether the view is loaded before checking whether the view is in window: `if (self.isViewLoaded && self.view.window != nil) ...` – rob mayoff Oct 09 '12 at 22:13
  • @rob. Yes, you are correct. If the view controller is not loaded and you access the `view` object, you'll cause lazy loading which could mean loading things into memory you aren't really ready to use. While it would still give the correct answer, it would present less than ideal performance. I had made the assumption that notifications would only be added when the view is loaded, not initialized, since an uninitialized view will never be attached. Still it was possibly an inappropriate assumption and one which should have been stated if nothing else. – DBD Oct 10 '12 at 12:52
  • 1
    This should really be the correct answer, with @robmayoff's change integrated. – Bill Oct 23 '15 at 19:35
  • agreed to @Bill... This should indeed be the accepted answer! – S1LENT WARRIOR Feb 05 '17 at 14:50
3

You can use flags in viewWillAppear and viewWillDisappear methods for this.

Rob
  • 415,655
  • 72
  • 787
  • 1,044
1

Why don't you remove the notification listener in viewWillDisappear and add it in viewWillAppear?

Edit: misread his question, sorry.

Suggested answer: set your own flag (BOOL) in viewDidDisappear and viewDidAppear.

yuf
  • 3,082
  • 3
  • 20
  • 18
  • This won't work because it will miss all the notifiations when it removed. – ikevin8me Oct 09 '12 at 20:41
  • Then what about setting a flag (BOOL) in viewWillDisappear to indicate the view is not visible anymore. When it receives a notification, check the flag to see if the view is visible. – yuf Oct 09 '12 at 20:43
  • If the notification comes I will need to reload the table. If it does not come, then it is too expensive to do that. Further, there is no need to reload the table when the view re-appears for the same reason: data is the same and too expensive. – ikevin8me Oct 09 '12 at 20:43
  • You mean I set a flag MYSELF when the view disappears? It is a strange solution, because I thought Apple's API has thought about that I can can detect it. How? – ikevin8me Oct 09 '12 at 20:44
  • I see what you mean; I was thinking about if you're pushing a view as a modal VC with a transparent background, if you'd consider the bottom view as visible or not. I would set my own flag because it gives me more control. I do not know if view.superview (other answer) will work but it seems plausible. – yuf Oct 09 '12 at 20:49
1

Specify title to each ViewController and then get the title of current ViewController by the code given bellow.

NSString *currentController = self.navigationController.visibleViewController.title;

Then check it by your title like this

if([currentController isEqualToString:@"myViewControllerTitle"]){

    //write your code according to View controller. 

}
tkanzakic
  • 5,499
  • 16
  • 34
  • 41
Neel Kamal
  • 221
  • 3
  • 2
0

I think that checking of viewController.view.superview should works.

Tomasz Dubik
  • 641
  • 4
  • 6
0

It's too late to replay on this question.

To check the instance of a UIViewController is currently on the top of the screen or to check if it is showing on screen, you can put a check like:

// Get the topmost view showing on the screen as below
    UIViewController * currentVC = ((UINavigationController*)app.window.rootViewController).visibleViewController;

// Now check whether the viewcontroller you want to show is the same as the currently showing view controller.
    if (currentVC.class == myVC.class) {  // Here myVC is any/new instance of the viewcontroller you would like to check or show (if not shown).
         // If both are same then it returns true and executes this block of code.
    }
Er. Vihar
  • 1,495
  • 1
  • 15
  • 29
0

One more alternative which is based on checking window property

if viewController.viewIfLoaded?.window != nil {
    // visible
}
yoAlex5
  • 29,217
  • 8
  • 193
  • 205