awakeFromNib() and windowDidLoad() - objective-c

Can anyone explain what awakeFromNib(), windowDidLoad(), init() does?
I am using a class which is inherited from NSWindowController, i found the precedence as
-init(), -awakeFromNib(), -windowDidLoad().
I want to know what these methods exactly perform.

init is the first method that gets called. This initializes self and all the ivars, properties etc.
awakeFromNib is called after init. When a nib is loaded, the nib loader allocates and initializes all objects, then hooks up all of their outlets and actions. Because of the order in which this happens, you cannot access outlets in your initializer. You can try, but they will all be nil.
After all outlets and actions are connected, the nib loader sends awakeFromNib to every object in the nib. This is where you can access outlets to set up default values or do configuration in code.
windowDidLoad is a delegate method which is called when window is fully loaded. Sent after the window owned by the receiver has been loaded. The default implementation does nothing.

Related

NSWindowController initialization warning

I am developing a document-based app. I am using a dedicated window controller for the document window, and calling the -[NSDocument makeWindowControllers] method.
My window controller is initialized like this:
- (instancetype) init
{
if (self = [super initWithWindowNibName:#"Document" owner:self]) {
}
return self;
}
Here, #"Document" is the .xib file containing the main document window that was created with the project.
The rationale here is that, this window controller is always initialized with this type of window, so the parameter is both hard-coded and hidden away inside the implementation of -init (while also conveniently setting the window owner to self).
So, the side that instantiates the window controller (in my case, the document class) doesn't need to worry about which nib to use and can just call -init.
The problem is, I am breaking the designated initializer chain and Xcode complains with these warnings:
Semantic Issue Method override for the designated initializer of the
superclass '-initWithCoder:' not found.
Semantic Issue Designated initializer missing a 'super' call to a
designated initializer of the super class.
Semantic Issue Method override for the designated initializer of the
superclass '-initWithWindow:' not found.
Semantic Issue Designated initializer invoked a non-designated
initializer.
I would switch the call to -initWithWindowNibName:owner: with one to -initWithWindow: (and after that, set the owner manually, I guess?); but I don't know how to create an NSWindow directly from a nib (or if this is the right thing to do).
EDIT: I just discovered that the warnings are being triggered only because I labeled -init as NS_DESIGNATED_INITIALIZER in my interface. I can remove that label and the warnings go away, but -init is my de-facto designated initializer so I would rather keep it.

NSWIndowController creating Outlets sequence of nib-loading

I'm having big trouble with a nib containing a NSWindowController (as Files Owner) plus ArrayControllers bound to the Files Owner in the nib.
The subclassed NSWindowController seems ok, but the NSObjectControllers, NSArrayControllers and 'custom' NSObjects within the nib are all set to 0x0 -- after a nib load.
All controllers and objects are properly 'bound' in IB. The NSObject subclss has a initWithCoder. Is there further requirements for inits or awake. I should not that ALL inits are essentially doing nothing, but return super. Thats because all referenced objects are set (bound) within the nib.
It seems it has something to do with the sequence of nib loading. And, I was led to believe that IBOutlets were available BEFORE awakeFromNib, following a [super initWithWindowNibName:name];
Based on the docs,
In Mac OS X v10.5 and later, setting an outlet also generates a
key-value observing (KVO) notification for any registered observers.
These notifications may occur before all inter-object connections are
reestablished and definitely occur before any awakeFromNib methods
of the objects have been called.
Moreover,
If you need to configure the objects in your nib file further at load
time, the most appropriate time to do so is after your nib-loading
call returns. At that point, all of the objects are created,
initialized, and ready for use.
Am I wrong to believe that self = [super initWithWindowNibName:name] is my nib-loading call?
Some of my awakeFromNib are called only when the Window is shown. ie. [myWindowController showWindow: nil]; My window is opened as a sheet that is making a blocking call, thus it is not easy to access those arraycontrollers after a showWindow.
Am I wrong to believe that self = [super initWithWindowNibName:name]
is my nib-loading call?
-[NSWindowController loadWindow] is the method that actually loads the nib. Not that you should ever call it directly; -[NSWindowController window] is the one you should call instead, because the latter invokes -[NSWindowController windowWillLoad] and -[NSWindowController windowDidLoad] as well.
The documentation for NSWindowController states:
Although a window controller can manage a programmatically created
window, it usually manages a window in a nib file. The nib file can
contain other top-level objects, including other windows, but the
window controller’s responsibility is this primary window.
The upshot of this is that nothing in the nib will be loaded until the window in it is loaded.
This is a "gotcha" that used to get me a few times!

How is view initialized when loaded via a storyboard?

When view is loaded manually, developer remains in control when it comes to initializations, we choose what initializer to call, what variables to set etc.
When view is loaded from the storyboard segue ... what happens to that initializer? Where should variables be set i'd like to be available once view had been loaded?
Please help me understand the sequence here. How is instance of the class created here, who creates it and how can we intervene and help set it up to our liking?
When a view is loaded from a nib or storyboard, it's -initWithCoder: method is called. Like -initWithFrame:, -initWithCoder: is a designated initializer for UIView. If you're going to do any custom initialization for a UIView subclass, you should make sure that it happens for both these methods. One common technique is to add a common initialization method that you call from both -initWithFrame: and -initWithCoder:. See my answer to Custom view and implementing init method? for a more detailed description.
Note that the documentation for -initWithFrame: explains:
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.

How to hookup a MainWindow.xib to an empty project

Beginning with XCode 4.2, when you create an empty project using XCode 4.2, a MainWindow.xib is no longer created and hooked up for you. I've found an article that describes how to do this and I've done it and it works, but if this process has taught me anything, it has shown me that I have no idea how main(), AppDelegate and the MainWindow.xib exist together.
http://www.trappers.tk/site/2011/06/16/mainwindow-xib/
Why is MainWindow.xib class updated to UIApplication?
Why is an object placed on the xib, and then AppDelegate class is selected for the class?
Why is the delegate outlet of the File Owner connected the AppDelegate object?
Why is the the window outlet of the AppDelegate to the Window?
why does - (BOOL) application:didFinishLaunchingWithOptions: need to be commented out.
I've researched around but, I'm still not 100% sure how everything is loaded up once the application starts, and why this is setup is needed just to have a MainWindow. I have a feeling though that I should probably get all these concepts down to continue to advance in iOS development.
Why is MainWindow.xib class updated to UIApplication?
At the lowest level, nib files are loaded with the method -[UINib instantiateWithOwner:options:]. The File's Owner in a nib file is a placeholder. In Xcode, it isn't a specific object yet. It will resolve to an actual object when the nib file is loaded. Its purpose is to relate, via outlets and actions, objects inside of the nib with the object that loaded the nib. The object passed as the "instantiateWithOwner:" parameter of that UINib method is what the File's Owner placeholder in Interface Builder will resolve to.
UIApplication loads the nib file specified in the info.plist and passes 'self' for the owner parameter when loading the nib file.
By setting the class name, you're just hinting to the tools so that they can suggest the set of actions and outlets you're allowed to establish.
Why is an object placed on the xib, and then AppDelegate class is selected for the class?
When you place the generic object in the xib and change its class to 'AppDelegate' you're telling Xcode to instantiate an instance of 'AppDelegate' when the file is loaded.
Why is the delegate outlet of the File Owner connected the AppDelegate object?
UIApplication has a 'delegate' that it delegates responsibility to and notifies when interesting events occur. When you make this connection, you're setting the delegate property of the application to be the instance that you specified above. From that point on, this instance will receive the delegate messages from UIApplication, like -application:didFinishLaunchingWithOptions:.
Why is the the window outlet of the AppDelegate to the Window?
Outlets are a way to refer to objects inside of a xib. They cause properties or instance variables to be set to refer to the object pointed to by the outlet. When you make this outlet, you're making it so that the app delegate instance you created above has a way to refer to the window that's also created when the xib is loaded.
why does - (BOOL) application:didFinishLaunchingWithOptions: need to be commented out.
It represents the code-focused way to do some of the same things that are happening in the xib, and if they were both present, they would be overwriting each other.
The object placed on the XIB file is the AppDelegate because it delegates all connections in the Interface Builder, meaning if you write a method that when a button is clicked it displays text, that method would be connected to either the App Delegate or the File's Owner, preferably the delegate. The File's Owner, since it is the UIApplication, connects to the delegate because it assigns that certain object to be the App Delegate. Sorry that I couldn't answer the rest of your questions, they didn't really make sense.
Hope this helps

How can I initialize a custom GUI class?

I'm developing an iPad app.
Now I ran into the following problem. I created a "Custom Class" for a UIScrollView. So in my nib file I have added a default UIScrollView and set the Custom Class to MultiSelectView (which is the custom class I created). Screenshot here.
So in my MultiSelectView I have added some methods that I want to use. This works!
The issue is that I'm wondering how I can initialize certain objects that I need in these methods. It seems like - (id)initWithFrame:(CGRect)frame {} is not called, and neither is - (void) viewDidLoad {}.
Thus, is there a way to initialize a custom (GUI) class?
When you unarchive a view from a .xib file, it is not sent -initWithFrame:, as you've noticed. Instead, it's sent -initWithCoder:.
So, if you've got any UIView subclass in a .xib file that needs custom initialization, you'll need to override -initWithCoder: as well as (or instead of) -initWithFrame:.
Looks like you need initWithCoder, it is called when object is loaded from NIB
Or, better, awakeFromNib. The difference is that awakeFromNib is called when all outlets are connected.