why awakeFromNib can't be called in controllers? [duplicate] - ios

This question already has answers here:
What is the process of a UIViewController birth (which method follows which)?
(7 answers)
Closed 9 years ago.
I am a new developer, two questions as follows
In controller, why can't I call the awakeFromNib method?
-(void)awakeFromeNib
{
NSLog(#"awakeFromNib");// can't be printed ?
}
Do the methods awakeFromNib and initWithNibName , layoutSubviews have some relations?
When and where should I use them?

- (void)awakeFromNib is only called inside of an object that is being directly loaded from a nib or storyboard. This is usually not a UIViewController.
So, the reason awakeFromNib is not on a view controller is that the view controller is the one that is calling its subviews to awake from the nib as set from the method initWithNibName:bundle:. The layoutSubviews method is also called in a subclass of UIView since a view may have subviews that it needs to layout. If I'm not mistaken, the layoutSubviews on a UIView gets called after awakeFromNib.
Hope this helps!

awakeFromNib is called on the controller after all the connections in it's nib are created and set up.
initWithNibName is the designated initialiser for the class. You call this when you are creating the controller in code.
layoutSubviews is a method that you implement that allows you to give precise layout to subviews.
You should also know about initWithCoder which is the initialiser that is called when the controller is created from a xib file or a storyboard.

Your view controller was likely not awaken from a NIB and instead initialized initWithNibName:bundle:. Only objects that are initialized from a NIB get awakeFromNib.
There is a method that gets called when the view is initialized, either from a NIB or loadView: viewDidLoad
Using viewDidLoad accomplishes pretty much the same thing you'd be expecting from awakeFromNib.
You may be able to use awakeFromNib when your view controller is created from a storyboard, as Abizem suggests, but that will still invoke viewDidLoad immediately afterward.

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.

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.

When to use viewDidLoad and when to use awakeFromNib

I've gotten pretty comfortable using the viewDidLoad method to execute things I want done at the beginning of a view, but reading one of Apple's tutorials they set the data controller for the class in the awakeFromNib method and did nothing in the awakeFromNib. I swapped it and it seemingly worked identically in my app, but I'm not sure if it was better to have it in awakeFromNib or viewDidLoad.
When should I use either one?
awakeFromNib is called when the associated nib file with a class is loaded . Any class that can own a nib can use it. viewDidLoad is used only by view controllers. It is usually called when loading from nib as well but it can also be called by a view created in memory (very rare circumstance.). If you are using controllers, then I would suggest you to use viewDidLoad
For more Refer this Answer
viewDidLoad is associated with the view controller. If you need to initialize another control unarchived from the nib (e.g. UITableViewCell prototype) you cannot overload viewDidLoad, you need to overload awakeFromNib.

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

Is it ok to call [super loadView]?

I thought that I should never call [super loadView] but something is confusing me.
In description of loadView (UIViewController Class Reference) it is said that "Your custom implementation of this method should not call super.",
but in ZoomingPDFViewer example that they gave, loadView implementation (ZoomingPDFViewerViewController) is calling [super loadView].
I have tried to call it from my loadView method and it works ok, but I just don't understand then what does it mean to not call super.
You definitely should not be calling [super loadView]. I'd say you found a bug in the ZoomingPDFViewer example.
You override loadView when you want to programatically create the view hierarchy for your view controller (not using a xib).
As you pointed out, the docs clearly state that you should not call super.
Your custom implementation of this method should not call super.
I assume this is to avoid loading both from a xib and programatically creating a view as this method is used by the base to load a view from a xib:
If the view controller has an associated nib file, this method loads
the view from the nib file.
Note also that even if during allocation of your UIViewController object you pass nil for the nibNameOrNil parameter that the UIViewController implementation of loadView will try to load any xib with the associated class name in it.
A view controller has an associated nib file if the nibName property
returns a non-nil value, which occurs if the view controller was
instantiated from a storyboard, if you explicitly assigned it a nib
file using the initWithNibName:bundle: method, or if iOS finds a nib
file in the app bundle with a name based on the view controller’s
class name. If the view controller does not have an associated nib
file, this method creates a plain UIView object instead.
The real intent of this method is to give you full control of building the view hierarchy without relying on the built in xib loading mechanism.:
You can override this method in order to create your views manually.
Personally, I override loadView if: 1.) The xib I would make for it is really trivial or 2.) The layout of the control is very dynamic, so creating a xib with a static layout has little benefit.
NSViewController tries to initialize a view from a nib in -loadView. Since your nib name is not set for your controller, it will just give you a self.view = nil; I would assume UIViewController works the same way.
So it should be safe, but you it's completely unnecessary.
If you dont have a view created in your IB, then you should call [super loadView] in your code to give a view to your program.
In case of your custom views, you are suppose to create a view with the interfaz builder, so you dont need to call it.
If you create your ViewController programmatically, you could call super.loadView() instead of self.view = UIView(frame: UIScreen.main.bounds) at the beginning of override func loadView().
However, do NOT call self.view before super.loadView(), since the former will trigger the latter if view did not been loaded.
I don't think it's a good idea to explain Apple's documentation like a robot.

Resources