When does awakeFromNib get called? - ios

Does awakeFromNib get called right after viewController is allocated and initialized?
At what precise point does the awakeFromNib of a view controller get called?
From my debugging session, I see that awakeFromNib for the rootViewController doesn't get called until [self.window makeKeyAndVisible] is executed.

awakeFromNib gets called after the view and its subviews were allocated and initialized. It is guaranteed that the view will have all its outlet instance variables set.
EDIT: A detailed recount of events:
During the instantiation process, each object in the archive is
unarchived and then initialized with the method befitting its type.
Cocoa views (and custom views that can be customized using an
associated Interface Builder palette) are initialized using their
initWithCoder: method. Custom views are initialized using their
initWithFrame: method. Custom classes that have been instantiated in
the nib are initialized using their init method.
Once all objects have been instantiated and initialized from the
archive, the nib loading code attempts to reestablish the connections
between each object’s outlets and the corresponding target objects. If
your custom objects have outlets, an NSNib object attempts to
reestablish any connections you created in Interface Builder. It
starts by trying to establish the connections using your object’s own
methods first. For each outlet that needs a connection, the NSNib
object looks for a method of the form setOutletName: in your object.
If that method exists, the NSNib object calls it, passing the target
object as a parameter. If you did not define a setter method with that
exact name, the NSNib object searches the object for an instance
variable (of type IBOutlet id) with the corresponding outlet name and
tries to set its value directly. If an instance variable with the
correct name cannot be found, initialization of that connection does
not occur. Finally, after all the objects are fully initialized, each
receives an awakeFromNib message.
Source
EDIT 2: This doesn't apply to view controllers loaded from storyboards.

When coder wants load a object that it haven't init yet.
Exp: Control in UITableViewCell will init when code call awakeFromNib that needn't cellforrow.

Related

What are outlets in awakeFromNib?

I see that when view controller is loaded from storyboard, these events happen in order
awakeAfterUsingCoder
awakeFromNib
viewDidLoad
In awakeFromNib, I see that isViewLoaded == false. From
Which should I use, -awakeFromNib or -viewDidLoad?
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.
In the spec of awakeFromNib
The nib-loading infrastructure sends an awakeFromNib message to each object recreated from a nib archive, but only after all the objects in the archive have been loaded and initialized. When an object receives an awakeFromNib message, it is guaranteed to have all its outlet and action connections already established.
So which outlet and action does it mention? The other thing is that awakeAfterUsingCoder is called 3 times in my case !!!
This only works with nibs. As I understand if we're loading ViewControllers from storyboard awakeFromNib gets called but before the view and subviews are initialised. That's why there is no guarantee that the view and outlets will be initialised. So if you need the object with established outlet and action connections you need to start awakeFromNib with [self view] it`s like a little trick that helps.

Objective-C iOS Development Using viewDidLoad or initWithCoder when setting Variables and Why?

So it seems like I should be setting my member variables in viewDidLoad - but I am confused as to why setting these variables in initWithCoder fails, since both are called at the start of the program.
In particular I have a line of code:
[worldView setMapType:MKMapTypeSatellite];
In which worldView is a IBOutlet MKMapView object. It works under viewDidLoad, but not initWithCoder.
The outlets are not yet connected when initWithCoder is called.
From the documentation:
During the instantiation process, each object in the archive is
unarchived and then initialized with the method befitting its type.
Objects that conform to the NSCoding protocol (including all
subclasses of UIView and UIViewController) are initialized using their
initWithCoder: method.
...
After all objects
have been instantiated and initialized, the nib-loading code
reestablishes the outlet and action connections for all of those
objects. It then calls the awakeFromNib method of the objects.
So awakeFromNib would be a suitable place for the custom setup of your UI elements.
The objects do not yet exist when initWithCoder is called, and they do when viewDidLoad is called. Check your initWithCoder method by logging out the value of worldView using something like:
NSLog(#"World View: %#", worldView);
and it will be nil. They will be initialized before the call to viewDidLoad, so you can set a property of that IBOutlet there.

Is it alright to call IOS property accessors inside a view controller's loadview when initializing?

In my project I am creating UIViewControllers without IB and hence without nib files, so all of the controller content, visible or otherwise, is created programatically in loadView: . Therefore I am essentially "initializing" all my objects in loadView:. Is this the right thing to do? Or should I put all my initialization in initWithNibName:bundle:?
As it is I am creating instances of my UIView subviews in the controller's loadView: like so:
self.mySubView = [[SubView alloc] initWithFrame:aframe];
[self.view addSubView:self.mySubView];
[self.mySubView release];
So I am instantiating several of these subviews using synthesized properties. And as I am not inside an initializer, I am creating these views by calling their accessors as above. But yet, it does feel like this is essentially initialization code and so perhaps I should be calling alloc/ init on my ivars directly and not through accessors, which then leads me to think that I should be doing this in initWithNibName:bundle:.
And if I am right to initialize objects in loadView:, should i really be using an accessor to alloc/ init?
Any thoughts?
At the time initWithNibName:bundle: is called (and here I am assuming you are NOT using a nib file), your view controller's controlled view is not yet created. It get's created the first time self.view is referenced. It is good practice to not do this in the init method. As a result, it follows that it is also good practice to not create your sub views in the init method.
The first time self.view is referenced in any way, the loadView method is automatically called by the view controller. It is your job to programmatically create the controlled view at this time. It is perfectly OK to create your subviews in the loadView method, and if you follow the good practice I suggested, you will need to. But you should only reference self.view in the loadView method for the purpose of assigning the controlled view to it, which means you should only be referencing it exactly once in the loadView method.
You should not be doing this in the loadView method:
[self.view addSubView:self.mySubView];
This is because you are referencing the controlled view while you are in the method that is called to create it. self.view isn't created for you, you have to create it in the 'loadView` method.
Instead, use a local variable to create the controlled view, then assign that local variable to self.view at the end of the loadView method.

If you're using a UIStoryboard, will UIViewController call awakeFromNib?

simple question,
If you're using a UIStoryboard, will UIViewController call awakeFromNib?
If not, what is the alternative method being called that we should use?
Cheers!
Yes, awakeFromNib will be called when using a UIStoryboard.
While a .storyboard file is a XML document, it will get converted to a set of traditional .nib files when you compile/package your app, so decoding those will be the same as in xib-based projects.
Yes, awakeFromNib is being called.
According to the documentation:
Initializing a View Controller Loaded from a Storyboard When you
create a view controller in a storyboard, the attributes you configure
in Interface Builder are stored in an archive. Later, when the view
controller is instantiated, this archive is loaded into memory and
processed. The result is a set of objects whose attributes match those
you set in Interface Builder. Here’s how that archive is loaded:
If your view controller implements an initWithCoder: method, that
method is called to process the information in the archive. If your
view controller does not implement an initWithCoder: method, your view
controller’s init method is called instead.
After the objects in the archive are loaded, iOS calls the awakeFromNib method on any objects
that implement such a method. You use this method to perform any
configuration steps that require other objects to already be
instantiated.
Yes awakeFromNib will be called when using a UIStoryboard.

On iPad, the initWithFrame of a new class based on UIView is not called?

For a single view app, a DrawView class is added, which is a subclass of the UIView class.
It is used as the main view for the app, so the drawRect method of this class works well, can draw things, for example, but the code generated by Xcode has a line "// Initialization code" to indicate putting init code right there, inside of initWithFrame, but I put some code in there and it is not called, and a break point is set there but it never stops there? I then added an init using the usual method and it is not called either?
Try overriding -(id)initWithCoder:(NSCoder*)coder. I believe when a view is loaded from a nib it uses this init method. See this question.
initWithCoder: -It is recommended that you Implement this method if you load your view from an Interface Builder nib file and your view requires custom initialization.The nib-loading code does not use the initWithFrame: method to instantiate new view objects. Instead, it uses the initWithCoder: method that is part of the NSCoding protocol.The nib-loading code does not use the initWithFrame: method to instantiate new view objects. Instead, it uses the initWithCoder: method that is part of the NSCoding protocol.apple's doc
initWithFrame: - The default initialization method for views,The new view object must be inserted into the view hierarchy of a window before it can be used. If you create a view object programmatically, this method is the designated initializer for the UIView class.
some more information here for :overriding methods
happy to help:)

Resources