initWithNibName VS viewDidLoad - objective-c

I've been trying to understand for hours when I should use the viewDidload: and when I should use initWithNibName: to set up the properties of my viewController.
For instance, I'm using a TableViewController and I'm setting all its properties (such as the backgroundColor, the separateColor, the toolbar items) in initWithNibName. It is the right way to do ?
If somebody could enlighten me.
Thanks

You should set up your properties in the viewDidLoad. This method is called by the system when the controller's view is loaded into memory. The initWithNibName: is something that you call when you create a controller instance from a nib file.
That is to say, that if you set up your properties in the initWithNibName: and instead you call init, your controller might not be in a good state; thus, it's best to do in viewDidLoad.

You should use viewDidLoad: method of your controller. To quote from Apple's documentation on initWithNib:
The nib file you specify is not loaded right away. It is loaded the first time the view controller’s view is accessed. If you want to perform additional initialization after the nib file is loaded, override the viewDidLoad method and perform your tasks there.

initWithNibName: is called when the NIB is loaded and instantiated.
viewDidLoad: is called when your view is actually presented onscreen.
And yes - I believe that in your case, setting colors and such are best done in initWithNibName

Related

Loading nib using loadNibNamed:owner:options: designate initializer

I have a nib file with its class (UIView) assigned to it in the inspector, So when I need to show that view I loaded it using the method :
loadNibNamed:owner:options:
So if I have to do some initialization when I load the nib, what is the way to know that in the nib's UIView class like the initWithNibName:bundle For the UIViewController?
I appreciate any help :)
You want to use a combination of initWithCoder: and awakeFromNib which are each called at different times during the instantiation (the former) and configuration (the latter).

Why does self.view call subview setter method?

I have a custom view controller with several subviews. Each of those subviews is connected to the view controller's .m file via IBOutlet properties. Those subviews have custom setters that adjust size of the other subviews depending on whether that subview is or is not displaying content.
Now it seems that these custom setters are being called by initWithCoder: prior to viewDidLoad being called. (I hope/assume this is normal.)
My issue is that calling self.view accesses the setter methods for self.view's subviews. My current understanding is that this should not be necessary. Can someone explain what's going on here? I'd rather this not happen as I'm not intending to set anything by accessing self.view.
Here is the code: https://github.com/kenmhaggerty/Sandbox
Calling self.view on a view controller causes it to load its view from the nib, if it hasn't already done so. This instantiates all objects in the nib (using initWithCoder:) and sets the values of any outlets (using your accessor methods). It then calls viewDidLoad, by which point everything in the nib will exist.
Your outlet setter methods are probably not an appropriate place to be making layout adjustments. Either use a constraint-based layout which will automatically adapt to changes in size of the subviews, or use viewDidLayoutSubviews, or use the methods you are using to pass model information to those subviews.

Why do some UIViewController properties become nil when not set using viewDidLoad?

This seems to happen when I am using a nib file to load the view . I need to set the datasources and delegates for some custom views progammatically . They work only if i set them in the viewDidLoad method . Setting them in the initializer , awakeFromNib etc all fail. Does anyone know the reason for this ?
When you create a view controller from a nib file, the UIViewController is first initialized and then loaded. So when the initWithNibName:bundle: method is called self.view and any other views loaded from the nib will be nil. Also it may happen that the views are unloaded (see viewDidUnload). That's why any view-related initialization needs to happen in viewDidLoad.

Making sure that objects in nibs are initialized before applicationDidFinishLaunching

and thanks for taking a look at my problem.
i have two view controllers in my app and each has its own nib file. an instance of controller1 is stored in MainWindow.xib and an instance of controller 2 is in Controller1.xib.
is there a way to make sure that controller 2 is initialized before the app delegate is sent applicationDiDFinishLaunching?
the actual setup is much more complicated with many other view controllers, so i really don't want to put everything into MainWindow.xib. plus doing so will reduce reusability.
thanks again!
is there a way to make sure that controller 2 is initialized before the app delegate is sent applicationDiDFinishLaunching?
No. Well, maybe yes, but it's not how view controllers are supposed to work. The view controller is there to defer the loading of the nib, which is a rather expensive operation, until the view is really, really necessary. So, if you need controller2 right when applicationDidFinishLaunching is called, you shouldn't put it inside the nib which is controlled by another view controller.
If I were you, I would stop instantiating the view controllers in the nib file at all, and just create them inside applicationDidFinishLaunching:, as in
-(void)applicationDidFinishLaunching:(UIApplication *)application
{
....
self.controller2=[[Controller2 alloc] init... ];
....
}
I believe applicationDidFinishLaunching is the absolute entry point in which you have control of the code. That's conceivably the earliest place to load anything.

Which should I use, -awakeFromNib or -viewDidLoad?

I recently had a problem in my app where some of the subviews I was creating in a UIViewController subclass's -awakeFromNib method were disappearing from the view. After some poking around I found that moving the code I had put in -awakeFromNib to -viewDidLoad solved the problem. Seems that -awakeFromNib gets called only once when the UIViewController is unarchived from the nib, and -viewDidLoad gets called every time the view is unarchived.
So what's the best practice? It looks like UIViewController's -awakeFromNib shouldn't be adding any views to the view, that kind of stuff should be done in -viewDidLoad. Am I understanding this correctly? Or am I more confused than I thought?
awakeFromNib is called when the controller itself is unarchived from a nib. viewDidLoad is called when the view is created/unarchived. This distinction is especially important when the controller's view is stored in a separate nib file.
Also important is that the awakeFromNib function will never be called after recovering from memory warning. But, the viewDidLoad function will be called.
Yes, it's correct. You shouldn't really rely on awakeFromNib to do that kind of tasks.
awakeFromNib is similar to an event that's called after deserialization in .NET. viewDidLoad is similar to Load event in .NET.
If you are familiar with the concepts from .NET, this should be enough, I think.
I'll try to answer by giving an example:
If define customCell class and customCell.xib file, and then load the cell by using
- (NSArray *)loadNibNamed:(NSString *)name owner:(id)owner options:(NSDictionary *)options, awakeFromNib gets called when the objects in the xib are unarchived.
If you define a customViewController, then when the customViewController is created using - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil. viewDidLoad will get called when it's loaded into view hierarchy.
Some related confusing methods:
(void)loadView; This is where subclasses should create their custom view hierarchy if they aren't using a nib. If you don't specify a nib name, then loadView will attempt to load a nib whose name is the same as your view controller's class. If no such nib exists, then you must either call -setView: before -view is invoked, or override the -loadView method to set up your views programatically. -loadView should never be called directly.
(void)viewDidLoad: Called after the view has been loaded. For viewControllers created in code, this is after -loadView. For view controllers unarchived from a nib, this is after the view is set.
For a ViewController, IBOutlets are available in viewDidLoad()
Here stackView represents an IBOutlet in a ViewController, stackView is nil in awakeFromNib, but it has been instantiated when viewDidLoad() is called.