What are outlets in awakeFromNib? - ios

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.

Related

AwakeFromNib has nil outlets

In my RootViewController, I have IBOutlets. I can access them by viewWillAppear but they are all nil in awakeFromNib()
I am calling super.awakeFromNib()
Why are they all nil? Doesn't the Apple document guarantee that all the outlets from my view controller are initialized when awakeFromNib is called?
https://developer.apple.com/documentation/objectivec/nsobject/1402907-awakefromnib
Quote from the apple dev docs:
When an object receives an awakeFromNib message, it is guaranteed to have all its outlet and action connections already established.
For a UIViewController method awakeFromNib is called when the controller is "awake" from Nib file. You should use viewDidLoad is you want to interact with outlets.

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

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.

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.

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.

When does awakeFromNib get called?

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.

Resources