47

Possible Duplicate:
How to tell if UIViewController's view is visible

I'm developing an app that processes a constant stream of incoming data from the network and provides a number of different UIViews for the user to view that data.

When certain model data gets updated based on the incoming stream from the network, I access the associated UIViewController or UITableViewController and do -setNeedsDisplay on it (in the case of UIViewController) or -reloadData (in the case of UITableViewController).

Is there a way to check if a given UIView is currently being displayed (beyond just being loaded) so that I only do -setNeedsDisplay or -reloadData if the user is currently looking at that UIView? It would seem that calling -setNeedsDisplay or reloadData on a view that the user is not currently looking at is a waste of processing power and wouldn't be good for battery life. When the user eventually switches over to a view that previously got updated, doing -setNeedsDisplay or reloadData on the -viewWillAppear would make more sense.

Thanks

Community
  • 1
  • 1
Paul
  • 5,043
  • 7
  • 24
  • 24

3 Answers3

135

After doing some research, I found this answer in a different question posted on here...This seems to be the best way...

The view's window property is non-nil if a view is currently visible, so check the main view in the view controller:

if (viewController.isViewLoaded && viewController.view.window){
    // viewController is visible
}
Besi
  • 22,579
  • 24
  • 131
  • 223
Paul
  • 5,043
  • 7
  • 24
  • 24
  • 5
    I just edited [the other question](http://stackoverflow.com/questions/2777438/how-to-tell-if-uiviewcontrollers-view-is-visible/2777460#2777460) to also check isViewLoaded first to avoid accidently loading the view which this code above will do. Make the test: `if (viewController.isViewLoaded && viewController.view.window) ...` – progrmr Mar 23 '11 at 21:23
  • 1
    This answer shouldn't really be marked as correct, since it will trigger the loading of the VC's view. See programer's answer linked above. – Nick Forge Feb 07 '12 at 04:21
  • 2
    This will give you false positives for viewControllers that are obstructed by other, modally displayed viewControllers -> not the right way. What this does is reliable checking of a viewController is NOT visible, but not the other way around. – Till Feb 13 '12 at 16:43
  • Yeah right, also `self.window == nil` when the view is invisible. – pronebird Feb 26 '13 at 22:20
  • Yes, this approach will not work with a UISplitViewController. – vincentjames501 Feb 04 '14 at 14:22
  • 1
    Technically speaking, this answer only indicates that the view is inside a window's view hierarchy. It doesn't say anything about the real visibility of that particular view (can be shifted away from screen, set hidden, or hidden by subviews...) – onekiloparsec May 02 '15 at 14:22
  • 1
    The comment is your code sample is misleading. Certainly there are cases where all your IF conditions are true and the viewController is NOT visible. For example, if the app is backgrounded. – Bradley Thomas Sep 01 '15 at 15:28
14

Add this to your controllers, or to a subclass of UIViewController that you can then subclass further. Access it using a property or the variable:

- (void)viewDidAppear:(BOOL)animated
{
 [super viewDidAppear:animated];
 visible = YES;
}

- (void)viewWillDisappear:(BOOL)animated
{
 visible = NO;
 [super viewWillDisappear:animated];
}
Peter DeWeese
  • 18,141
  • 8
  • 79
  • 101
  • 1
    Also, don't do this as a category. Redefining methods in a category is bad practice. – Brian King Mar 01 '11 at 19:38
  • 1
    This would be a disaster in a category because you won't be able to define any class-specific behavior to occur on viewDidAppear or ViewWillAppear. – jpswain Jan 10 '12 at 22:55
  • Of course you could still define class-specific behavior. You can override methods and still call the super method. This is an old post though, and I see that a category wouldn't be useful because you'd need to store `visible`. I'll edit it. – Peter DeWeese Jan 11 '12 at 00:09
  • Using an instance variable here is not the best solution. A stateless solution like Paul suggested above is much better. – Jpoliachik Sep 10 '15 at 21:27
-3

Just for completeness, I thought I'd add in how to determine if the view controller is being displayed in a tab based app:

+(BOOL) isSelectedViewController:(UIViewController *)someVC;
{
    myAppDelegate   *appD = [[UIApplication sharedApplication] delegate];
    UIViewController *selectedVC = [appD.TabBarController selectedViewController];

    return selectedVC == someVC;
}
software evolved
  • 4,314
  • 35
  • 45
  • 2
    It would be much nicer to use (myViewController.tabBarController.selectedViewController == myViewController.navigationController), assuming you're nesting navigation controllers within the tab bar controller. – Johnus Mar 06 '12 at 00:54
  • I suppose if you know that the sub-controller is a navigation controller, but that is often not the case. – software evolved Apr 06 '12 at 16:13