viewDidLoad getting called twice on rootViewController at launch
You can't assume viewDidLoad will be called only once. If you are initializing objects and want a guarantee do the initialization either in the init method or if you are loading from a nib file from the awakeFromNib method.
I had this same issue when my app was first launching. What I found was that in my MainWindow.xib file, I was setting both my App Delegate's viewController
outlet, and my Window's rootViewController
outlet to my root view controller. When you build a View Based project file in Xcode, your App Delegate's didFinishLaunchingWithOptions
will be pre-populated with:
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
return YES;
I believe that the self.viewController
ivar is instantiated from MainWindow.xib before didFinishLaunchingWithOptions
gets called. Then the pre-populated code above sets the Window's rootViewController
. So if, in conjunction, you specify the rootViewController
outlet for the Window in your MainWindow.xib file, your root view controller will actually be created twice and added as the Window's root view controller two times.
Weird. I haven't seen this particular case, but in general, you ought to assume that viewDidLoad can be called multiple times. It'll get called whenever a nib file that references that controller gets loaded.
For a simple app with only one nib, that shouldn't happen. But in a more-complex app that can load and unload view controllers, this happens all the time.
I did some debugging and here's what I found about the ViewController
loading order:
initWithNibName:bundle: self = <original instance>, retainedOutlet = 0x0
loadView >>> self = <original instance>, retainedOutlet = 0x0
initWithCoder: self = <coder instance>, retainedOutlet = 0x0
initWithCoder: self = <coder instance>, retainedOutlet = 0x0
setView: self = <original instance>, retainedOutlet = 0x0
setRetainedOutlet: self = <original instance>, retainedOutlet = 0x1613c40
viewDidLoad self = <coder instance>, retainedOutlet = 0x0
awakeFromNib self = <coder instance>, retainedOutlet = 0x0
loadView <<<
viewDidLoad self = <original instance>, retainedOutlet = 0x1613c40
viewWillAppear: self = <original instance>, retainedOutlet = 0x1613c40
dealloc self = <coder instance>, retainedOutlet = 0x0
viewDidAppear: self = <original instance>, retainedOutlet = 0x1613c40
During the loadView method, initWithCoder:
is called and a new copy of the viewController
is created. this is what is passed into a few of the methods (like viewDidLoad
). the copy is destroyed later in a dealloc call. the good news is that in this copy, retained outlets are not configured, so you can use this as a test to know if you should initialize variables, call other methods, and most importantly, if you should release and destroy objects during dealloc.
Key takeaway: the real viewController
will have its retained IBOutlet
properties configured. if you are in an overridden method that is getting called multiple times, just check one of your retained IBOutlet
properties for NULL
. if they are NULL
, then return immediately.
Anybody got any clues as to why this is happening this way?
Side effect of this: you can't use awakeFromNib
reliably.