Loading nib using loadNibNamed:owner:options: designate initializer - objective-c

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).

Related

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.

Subclassing in IB

I have UIScrollView added to the main window of the app with IB.
What I want is that view to subclass UICustomScrollView instead of UIScrollView. To do that I choose the UIScrollView and then I change Custom class to UICustomScrollView in identity inspector. I have put some NSLog messages in init method of UICustomScrollView. When I run the app UICustomScrollView seem like it is not used because NSLog messages in init are not printed.
What I miss here ?
Here's what the UIView Class Reference has to say about initWithFrame::
If you use Interface Builder to design your interface, this method is not called when your view objects are subsequently loaded from the nib file. Objects in a nib file are reconstituted and then initialized using their initWithCoder: method, which modifies the attributes of the view to match the attributes stored in the nib file.
If your NSLog is only in initWithFrame, it won't be called if the view is loaded from a nib.

What awakeFromNib really is?

I'm just a newbie of Objective C iPhone programming... I see a lot of codes that contains method named "awakeFromNib".. What does it really mean? how and when and where to call this method?
Thanks...
awakeFromNib is called for objects (views, controllers, etc.) that are being archived in xib/nib files. This basically means that xib/nib was unarchived, all connections (IBActions/IBOutlets) for all objects are made and you have a working object graph.
I use it when I have a custom view class that I gave to a certain view in my xib.
You don't call it. After nib file load, every view inside of it, be it button, UIView or something else, calls awakeFromNib from their respective class automatically. You override this method for setup and layout, as you would do with init method if you were creating a subview programmatically.

initWithNibName VS viewDidLoad

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

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.