1

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];
}
Black Frog
  • 11,595
  • 1
  • 35
  • 66
HM1
  • 1,684
  • 2
  • 18
  • 25

5 Answers5

9

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.

Jonah
  • 17,918
  • 1
  • 43
  • 70
  • Thanks Jonah. I think I understand what's going on. Using addSubView is more for adding smaller view's to a VC e.g. UILabel, UIImage, a custom UIView, all things that will compose the current VC's view. It's not meant for stacking a complete view of VC#2 on top of current VC#1. For that, I need to use NavControllers, TabControllers or MyCustomControllers. Using addSubView works in appDelegate becoz the appDelegate & MainWindow has only added a UIWindow to the screen. To get a view, u need to add a VC with an associated view and since that's the only view stacked on the display, it works fine. – HM1 Mar 29 '11 at 06:09
  • That's right. Each of those sub views could still have controller objects responsible for managing them. Their controllers should just not be UIViewControllers. For example you might have a UITableView as a subview and a controller which acts as its delegate and datasource. That way your avoid having a single monolithic controller class. – Jonah Mar 29 '11 at 16:15
  • I'm certainly guilty for adding the views of UIViewController subclasses to the views of other UIViewController subclasses. I for one thought this was more or less the whole idea of the UIKit MVC model... – averydev Apr 17 '11 at 02:54
  • I've split off my questions regarding this topic to another thread: http://stackoverflow.com/questions/5691226/am-i-abusing-uiviewcontroller-subclassing – averydev Apr 17 '11 at 03:27
  • @ScottAllen thanks but please be aware that is answer is fairly old. In iOS 5 and it is valid to create container view controllers whose children manage a small part of the parent view. You still need to work with the framework and use the appropriate add/remove child view controller methods in order for UIViewController methods like -viewWillAppear: to be called when you expect but at least you have some more options for nesting view controllers now. – Jonah Jun 25 '13 at 18:51
4

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

HeikoG
  • 861
  • 10
  • 11
  • HeikoG, this was not the case. I was using the standard template UIViewControllers generated by Xcode. This question was during iOS4 so things may have changed now. – HM1 Feb 04 '13 at 16:56
2

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.

Anomie
  • 92,546
  • 13
  • 126
  • 145
0

Just try this.. I got it working :)

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

  // updating ivars with data
}
Shrey
  • 1,959
  • 2
  • 21
  • 44
0

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.

AechoLiu
  • 17,522
  • 9
  • 100
  • 118
  • ModalVC is not for navigating through VC's according to Apple's guidelines. PushVC is associated with NavController and that's something I didn't want to use but after researching @Jonah's comment, it's what I can use to solve the issue. I did try calling viewWillAppear:animated manually and the app crashes so that doesn't work. – HM1 Mar 29 '11 at 06:16