viewDidLoad calling before init? - ios

I face a strange situation. In my controller, viewDidLoad is calling before init. Is there any technical reason behind that?

The viewDidLoad method is being called when accessing self.view inside the init method (since self.view should not yet be loaded from the nib the process seems to be fasten so it doesn't return nil).

I know this is a bit old post, but I'll post my point of view anywhere because I think it could help somebody.
Well, I've been in this same situation. I thought that viewDidLoad was being called before init method in my view controller class. But what was really happening was not that: the flow starts on init method, but jumps to viewDidLoad when calling [super init*], so my log messages in viewDidLoad method were being displayed first that those in my custom initialization.
I think that's it. I hope this to save some time to someone.
[Sorry for my English]

NOTE for UITabBarController:
I don't know what kind of UIViewController caused this for you but I faced a similar case with UITabBarController.
I thought it might help another one facing it with UITabBarController.
As far as I know all viewControllers call init before viewDidLoad, except for the UITabBarController and its subclasses.
As Andrew claims here, UITabBarControllers call loadView inside [super init] method, which causes the call to viewDidLoad. So the viewDidLoad method will be called before init has finished its job.
If you have some thing to setup in viewDidLoad you should perhaps do it inside init method after the call to [super init].

When you initialise a UIViewController from code, you use -initWithNibName:bundle:, whereas when it is initialised from a XIB, the XIB loading code will call -initWithCoder:. One, and only one of these two methods will be called, and they will definitely be called before -viewDidLoad.
There's no conceivable way that -viewDidLoad could be called first, unless you are calling it yourself (which you should never really do).

No, the viewDidLoad message is always called after init.
Are you sure init is called at all? There are several init methods especially for UIViewController, maybe another one is called instead making you think differently.
If you need more information, please paste the code of viewDidLoad and all of your init methods, and tell us how it is loaded (i.e. with code) or from a nib.

If your ViewController is being loaded from your main nib file, then most likely it is initWithCoder that is being called to initialize the controller.

Related

UIViewController, storyboards, no init method

I am using storyboards, and I have one UIViewController that is being opened modally.
When the UIViewController is being loaded, it never hits any of the init methods
init, initwithcoder, or initwithnib.
Why not?
I need to initialize some variables there!!
awakeFromNib was the answer, #Fogmiester got it, don't know how to make it his answer though!!
you can use viewDidLoad function and it also call once for each control object.
Thanks

About viewController's "viewDidLoad" and "viewWillAppear" methods

I've got a question regarding the two mentioned methods, since in my tests I don´t make clear the order they are called. I thought that, firstly, viewDidLoad is called when the viewController is loaded for first time (as the name indicates), and inmediately after the init method. Then, I thought that once viewDidLoad returns, viewWillAppear is called. If you display another viewController, and then you return to this one, then it should be already loaded and only viewWillAppear will be called.
However, while developing I make the impression that there is no order when calling viewDidLoad and viewWillAppear... I couldn´t find a clear description of this lifecycle in Apple's documentation, how does this actually work?
Thanks!
I would like to add to Caleb's answer: Don't confuse the view controller and the view! The name viewDidLoad clearly indicates that the method is invoked after the view has been loaded. It is the view controller that does the loading.
Some pointers regarding the lifecycle of views and the order in which messages are sent:
Not an official Apple document, but I find this diagram really useful because it includes pretty much all of UIViewController's lifecycle overrides.
In the section Resource Management in View Controllers from Apple's "View Controller Programming Guide" there is a flowchart that depicts how views are initially loaded. It explains loadView and viewDidLoad, also in conjunction with storyboards.
The section Responding to Display-Related Notifications from Apple's "View Controller Programming Guide" explains how to respond to views appearing and disappearing (viewWillAppear: et al)
If you are planning on implementing a container view controller: The UIViewController class reference has a good overview of how messages need to be sent by your subclass.
I'm stopping here. You can find more stuff yourself by googling for "uiviewcontroller life cycle".
-viewDidLoad is called when the controller loads its view, which is not necessarily right after initialization. View controllers don't load their views until they need them, either to display or for any other reason.
-viewWillAppear is called just before the view is displayed. This will be after -viewDidLoad, but you don't know exactly how long after. -viewWillAppear is called every time the view is displayed; -viewDidLoad will only be called a second time if the view is unloaded at some point (such as didReceiveMemoryWarning). These days that's unusual, but it can happen.
Or if the viewController is set to nil, which can usually happen if a view controller is kicked off the navigation stack, and therefore next time it is brought to the navigation stack it needs to call -viewDidLoad again.
I thought that, firstly, viewDidLoad is called when the viewController
is loaded for first time (as the name indicates), and inmediately after the init method
No. The name indicates that the controller's view has been loaded (not the controller itself). Actually the docs state that this method will get called after the view hierarchy has been loaded into memory (either via loadView or through a nib for example).
Then, I thought that once viewDidLoad returns, viewWillAppear is
called
Again, no. loadView (and as a consequence viewDidLoad) method will get called the first time that view property is to be accessed and is nil (which is the case when you're initializing a controller). Think of this simple scenario:
MyViewController *vc = [[MyViewController alloc] init];
UIView *view = vc.view; // <= loadView & viewDidLoad will fire but it certainly didn't appear...
However, while developing I make the impression that there is no order
when calling viewDidLoad and viewWillAppear...
Well there is an order. We know for sure that viewWillAppear will always be called after viewDidLoad (if both of them are to be called of course).
As you said, ViewDidLoad is only calling once after loading the view. So we can initialize the instances in the viewDidLoad. It is mainly meant for the initialization.
viewWillAppear will invoke whenever we reach to this view. So if there is any changes in UI, we can done it in viewWillAppear.
I ran a trace on when all these calls are made: http://thecodist.com/article/ios_arc_storyboards_and_uiviewcontroller_trace

On iOS, how do applicationDidBecomeActive, loadView, and viewDidLoad get called?

The methods applicationDidBecomeActive, loadView, and viewDidLoad will get called at appropriate times in an iOS app. For loadView and viewDidLoad, it looks like it is:
-(void) someMethod {
//...
[viewController loadView];
[viewController viewDidLoad];
}
Is that how they get called and what is the class that call them? (Is there source code that can show the flow of the starting of an app? A lot of times, we can only see the header files but not the source code).
If I understood well your question, you would like to know about the application lifecycle, is it true?
Well, I guess there is no source code provided by apple that can display you how it looks like.
If you want to know how happens when an application starts, I suggest to read about app-launch-sequence-ios-revisited by Oleb. It's a very good post.
About the methods you wrote, these methods shouldn't not called manually. It's the framework (through the iOS) that calls them for you.
The methods loadView and viewDidLoad are methods that are called during the UIViewController lifecycle.
You use (override) loadView when you cannot create a storyboard or a nib file. In this manner you can provide to your UIViewController a fresh view. From Apple doc:
If you cannot define your views in a storyboard or a nib file,
override the loadView method to manually instantiate a view hierarchy
and assign it to the view property.
In other words:
- (void)loadView
{
UIView* myCustomView = ... // create the view here
self.view = myCustomView;
}
About the viewDidLoad method, this is called when a view has been set up in memory. Once done you are sure that outlets, for example, are set up and you can perform additional initializations.
From Apple doc:
This method is called after the view controller has loaded its view
hierarchy into memory. This method is called regardless of whether the
view hierarchy was loaded from a nib file or created programmatically
in the loadView method. You usually override this method to perform
additional initialization on views that were loaded from nib files.
In other words:
- (void)viewDidLoad
{
[super viewDidLoad];
// additional initializations here
}
Finally, about applicationDidBecomeActive method (or delegate if you want), this is called to let your application know that it moved from the inactive to active state.
I suggest you to read UIApplicationDelegate and UIViewController class references.
If you want to simply verify the sequence call, override the methods and put a NSLog there.
Hope it helps.

Proper use of loadView and viewDidLoad with UIViewController without nibs/xibs

When I program without a nib, I am under the impression that I need to call loadView to initialize my view, like this:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nil bundle:nil];
if (self) {
// Custom initialization
[self loadView];
}
return self;
}
(I have set nibNameOrNil = nil, since there is not nib.)
Then, I set up the view, like this:
- (void) loadView {
self.view = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 367)];
[self viewDidLoad];
}
This is do everything else in viewDidLoad.
I'm still unsure if I am supposed to make the calls to loadView and viewDidLoad in this way. They are not getting called automatically.
What is confusing is in the documentation for the UIViewController class reference:
loadView Discussion
You should never call this method directly. The view controller calls
this method when the view property is requested but is currently nil.
If you create your views manually, you must override this method and
use it to create your views. If you use Interface Builder to create
your views and initialize the view controller—that is, you initialize
the view using the initWithNibName:bundle: method, set the nibName and
nibBundle properties directly, or create both your views and view
controller in Interface Builder—then you must not override this
method.
So, I don't understand how loadView gets called if I should never call it directly.
The default implementation of this method looks for valid nib
information and uses that information to load the associated nib file.
If no nib information is specified, the default implementation creates
a plain UIView object and makes it the main view.
I don't understand how that works -- the creation of a pain UIView.
If you override this method in order to create your views manually,
you should do so and assign the root view of your hierarchy to the
view property. (The views you create should be unique instances and
should not be shared with any other view controller object.) Your
custom implementation of this method should not call super.
If you want to perform any additional initialization of your views, do
so in the viewDidLoad method. In iOS 3.0 and later, you should also
override the viewDidUnload method to release any references to the
view or its contents.
Okay, so far it doesn't say how viewDidLoad is called. So for viewDidLoad:
viewDidLoad Discussion
This method is called after the view controller has loaded its
associated views into memory. This method is called regardless of
whether the views were stored in a nib file or created
programmatically in the loadView method. This method is most commonly
used to perform additional initialization steps on views that are
loaded from nib files.
Called by what?
Since These methods are not getting called automatically in my code, I am left to think that I have to call them myself. But I still don't get a clear understanding form the documentation that this is the right thing to do.
As the documentation says, you should not call these methods yourself.
How this is meant to work is that UIKit's code will call your loadView method if and when it actually needs to present that controller's view hierarchy on screen.
Specifically, if any code attempts to read your view property on your view controller, and that property is nil, then UIViewController's code will call the loadView method. If you don't implement loadView yourself, then the default implementation will fall back to attempting to load the view hierarchy from the nib.
This all happens automatically when you attempt to present your view controller and the view is nil. (This can happen multiple times while your app is running if your view controller has to unload its view in response to memory pressure, another behavior you get for 'free' and that you don't want to call yourself)
If these methods are not being called in your view controller, then there must be something wrong with how you are presenting this view controller, which is preventing the framework code in UIViewController from calling these methods. Post that code and someone can help you figure out that bug.
Before you attempt to fix that bug, though, you should remove these from your code:
[self loadView]
[self viewDidLoad]
And then in your own implementation of viewDidLoad, you will want to call the superclass' implementation with [super viewDidLoad]
Remember that in loadView your only responsibility to set self.view to some valid view. That's it. UIKit code will then see that and call viewDidLoad for you.
Hope that helps.
The answer by Firoze Lafeer is correct, I just want to show how to force load the view property the correct way:
(void)self.view;
You should not do this! If you must, you are doing something wrong, but do not call -loadView and -viewDidLoad yourself at any circumstances.

viewDidLoad is called twice

My viewDidLoad in a view controller is called twice. Once by [UIViewController View] and a second time by [UINib instanciateWithOwner:Options]. Why is this happening? Can it be prevented?
Any code you put inside of viewDidLoad should be able to run multiple times with out any issues. If you have code that only needs to run once for your controller use -awakeFromNib. The reason is because the view of the view controller can be unloaded and loaded multiple times. The code inside of viewDidLoad should only modify the UI to reflect the current state.
Now that I got that out of the way, your particular issue looks to be a bug. See Ned's answer.
Is this the same problem?
Why is viewDidLoad called twice when the rootViewController property of UIWindow is set?
Looks like it might be a bug in XCode 4.
You might have to check the object building mechanism. If there is only one nib file with reference to the controller, then this method should not be called multiple times. (unless if the object is getting rebuilt).
I think you might have to make your code within ViewDidLoad idemPotent. It is always better to make sure, that framework call back methods make this assumption.
There are two possibilities, whereby this issue happened in my iOS device frequently.
Rule #1: Do not call any view related setup in [init] function, all view related setup must be done in viewDidLoad and viewWillAppear.
Rule #2: Check viewDidLoad and viewWillAppear, are they calling correct super function? For example viewDidLoad -> super viewDidLoad and so on.
Hope this helps.
In my case, I used self.view (once) in viewDidLoad while calling viewDidLoad in my unit tests. This resulted in two calls. However, when I replaced [testedViewController viewDidLoad] with [testedViewController view], the double call problem was gone.
Debugging this showed that viewDidLoad was called a second time by #IBInspectable. The root controller is a UITabbarController. #IBInspectable was setting the tab in the storyboard. Not sure if this is a UIKit bug but try checking for this. You should never need to check viewDidLoad for double calls if your project is setup correctly.

Resources