5

I'm running all my apps to make sure it's not just one app, and in every app I have, when I run on the iOS5 simulator or device, the viewWillAppear method gets called twice on every view. I have a simple NSLog(@"1");, and this appears twice in my console every time. Is this just me, or is something going on? (It only gets called once in iOS4)

This is the code calling the view that calls viewWillAppear twice:

     CloseDoorViewController *closeVC;

     if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
            closeVC = [[ CloseDoorViewController alloc] initWithNibName:@"CloseDoorViewIpad" bundle:nil];
        } else {
            closeVC = [[ CloseDoorViewController alloc] initWithNibName:@"CloseDoorViewController" bundle:nil];
        }

        [self.view addSubview:closeVC.view];
        [self presentModalViewController:closeVC animated:NO];
Snowman
  • 31,411
  • 46
  • 180
  • 303

4 Answers4

16

It's the -addSubview: method.

When adding or removing view controller's view, someone must call 'View Event' methods such as -viewWillAppear:, etc. of the view controller.

Actually, it wasn't a recommended way to -addSubview:/-removeFromSuperView view controller's view by yourself before iOS 5, because it doesn't call 'View Event' methods (you can/should call it by yourself). Instead, it was recommended to use 'indirect' way to do that, such as -presentModalViewController: you use (it does call 'View Event' methods on your behalf).

On iOS 5, Apple has changed the behavior of -addSubview:/-removeFromSuperView methods to allow direct view management of view controller. So now, when you use those methods on viewController's view, 'View Event' methods will be called automatically.

So it was called twice.

See video "Implementing UIViewController Containment" on here also.

ppm
  • 260
  • 1
  • 7
  • 1
    Small note: viewWillAppear is called on iOS < 5 when adding views to the window. – Steven Kramer Jan 19 '12 at 10:45
  • This should be the accepted answer. I have been going crazy trying to figure out why since iOS5 addSubview/removeFromSuperview has been behaving differently. – daveMac Nov 27 '13 at 15:51
10

Because you are displaying the view twice.

First time by adding the view as a subview of the current view:

[self.view addSubview:closeVC.view];

Second time by pushing the view's controller on top of current view's controller:

[self presentModalViewController:closeVC animated:NO];

I'm not sure why in iOS4 the viewWillAppear was only called once, because iOS5 is correct to call it twice, given that you are displaying the view twice as explained above.

Just remove one of the lines and it would be fine (I'd recommend removing the addSubview and retain the presentModalViewController one).

Lukman
  • 18,462
  • 6
  • 56
  • 66
  • Oh wow didn't know that. Don't know why but I've been doing that all along. Question: If this is the way I'm presenting my view, where and when would I now release that CloseVC? – Snowman Oct 18 '11 at 16:44
  • You can release or autorelease it right there in the snippet posted — you no longer need an owning reference because you're not going to use the pointer again. – Tommy Oct 18 '11 at 16:56
  • 2
    @mohabitar or you migrate your code to use the "automatic reference count" and you don't have to worry about retain, release and autorelease anymore. – d.ennis Oct 18 '11 at 17:03
  • How do I enable automatic reference count? – Snowman Oct 18 '11 at 17:06
  • NM, found a link: http://www.mikeash.com/pyblog/friday-qa-2011-09-30-automatic-reference-counting.html – Snowman Oct 18 '11 at 17:11
  • Also Apple's documentation says that you should not add a `UIViewController`'s `view` directly into a view hierarchy. That's not the way View Controllers are supposed to be used and can cause lots of undesired behaviors. – Rivera Jan 20 '14 at 06:58
5

If you want to restore the old (iOS 4) behavior in your view controller you should implement the following method:

- (BOOL)automaticallyForwardAppearanceAndRotationMethodsToChildViewControllers {
    return NO;
}
Werner Altewischer
  • 10,080
  • 4
  • 53
  • 60
1

Update: since you have edited your question to include a code sample, it is clear what the problem is. Lukman's answer above is correct/excellent.

Original answer before code was included:

I would try putting a breakpoint (or log statement) in the -init method of this class. If that is hit twice, then two view controllers are being created.

(note if you have not already overridden the -init method in this class, make sure you override the designated initializer which is -[UIViewController initWithNibName:bundle:])

http://developer.apple.com/library/ios/#DOCUMENTATION/UIKit/Reference/UIViewController_Class/Reference/Reference.html

Todd Ditchendorf
  • 11,217
  • 14
  • 69
  • 123