1
votes

I'm stuck! I can't see why viewWillAppear doesn't run in my code but viewDidLoad runs. If I understand it correctly viewDidLoad runs once on the first instance and viewWillAppear runs every time a view is added to the stack of views to display.

I see others have had this issue but some how their solutions of calling viewWillAppear directly causes my app to crash. Other solutions were related to Navigation Controller and pushingView's but thats not what i'm using either! What am I missing?

Thanks in advance for your help! :)

See below: View Controller #1 - Currently being displayed on screen

-(IBAction)someButtonPressed:(id)sender{
  NSLog(@"FirstViewController - someButtonPressed");
  SecondViewController *secondViewController = [[SecondViewController alloc] initWithNibName:@"SecondViewController" bundle:nil];
  secondViewController.myLocation = self.myLocation;
  secondViewController.myDatabase = self.myDatabase;
  [self.view addSubview:secondViewController.view];
  //[secondViewController viewWillAppear:YES];
}

SecondViewController:

- (void)viewWillAppear:(BOOL)animated {
  NSLog(@"SecondViewController - viewWillAppear");
  [super viewWillAppear:animated];
  // updating ivars with data
}


// Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
- (void)viewDidLoad {   
    NSLog(@"SecondViewController - viewDidLoad");
    [super viewDidLoad];
}
5

5 Answers

9
votes

If I understand it correctly viewDidLoad runs once on the first instance and viewWillAppear runs every time a view is added to the stack of views to display.

-viewDidLoad is called every time a UIViewController's view is loaded. That may be many times during a single controller's life as the view may be unloaded to free up memory when it is not visible and reloaded, triggering another call to -viewDidLoad, when needed.

-viewWillAppear: is called when a UIViewController's view becomes visible. However UIKit assumes that UIViewController's views will fill their window. Nesting UIViewControllers' views is an example of abusing UIViewControllers and will result in unexpected behavior. As you have seen.

See About Custom View Controllers in the View Controller Programming Guide for iOS:

Each custom view controller object you create is responsible for managing all of the views in a single view hierarchy. In iPhone applications, the views in a view hierarchy traditionally cover the entire screen, but in iPad applications they may cover only a portion of the screen. The one-to-one correspondence between a view controller and the views in its view hierarchy is the key design consideration. You should not use multiple custom view controllers to manage different portions of the same view hierarchy. Similarly, you should not use a single custom view controller object to manage multiple screens worth of content.

4
votes

If you wrote a custom UIViewController Container you might have overwritten the following method, which leads to your described behavior.

- (BOOL)shouldAutomaticallyForwardAppearanceMethods{
    return NO;
}

In this case you have to manually handle beginAppearanceTransition/endAppearanceTransition. See Apples View Controller Containment article

2
votes

viewWillAppear: is called when a view controller is displayed in one of the normal ways (e.g. by selecting a tab in a UITabBarController, by pushing onto a UINavigationController, by being popped back to in a UINavigationController, by being presented with presentModalViewController:animated, by being uncovered after dismissModalViewControllerAnimated:, etc). Just displaying a view with addSubview: does not call the method.

It is possible to correctly call viewWillAppear: manually, but in general it's better to use one of the normal ways mentioned above.

0
votes

Just try this.. I got it working :)

- (void)viewWillAppear:(BOOL)animated {
  [super viewWillAppear:animated]; 
  NSLog(@"SecondViewController - viewWillAppear");

  // updating ivars with data
}
0
votes

When you push view or present a view controller by pushViewController:animated or presentModelViewController:animated:, they will call viewWillAppear:animated:, and else method for you. But if you addSubview: manually, you need to call those method by self.