awakeFromNib from nib1 got called when programmatically load nib2 - objective-c

When I loaded nib2 from nib1 with the syntax below, the awakeFromNib method from my current nib (nib1) got called again. (But not the initWithFrame method) Even though the nib2 was opened and got the focus correctly. I do not want the awakeFromNib from the nib1 to be executed again. What do I miss?
[NSBundle loadNibNamed:#"iQueryWindow" owner:self];
More info: iQueryWindow.xib has a iQueryView.h and iQueryView.m subclass of NSView associated with it to create the window view with button, textfield, etc. The sequence of event looked like this: I clicked a button from nib1 view, its clicked event only has a single line of code as above to open nib2's window. Nib2's window opened with all initialization including inintWithFrame and awakeFromNib methods of its (nib2) own. After that I can observed that nib1's window changed due to its own awakeFromNib got called (I can also observed this via the Console with the help of NSlog statement). (nib2's window displayed on top of nib1's.) There is a button on nib2 that will close nib2 with this: [self.window close].

-awakeFromNib is sent to all objects in the nib file, including the file’s owner. If you have an object that’s loaded from a nib file and make that object the owner of another nib file, it’ll receive -awakeFromNib twice. This happens by design.
Although you could have an ivar to manage the state of your class with regard to awakening from nib, consider using a subclass of NSViewController (or NSWindowController; it’s not really clear whether the nib2 has a view or a window as one of its top-level objects) as the file’s owner of the secondary nib file.

Per Bavarious suggestion, I use NSWindowController instead of NSBundle to resolve this issue. Here is the code:
NSWindowController *iQWController = [[NSWindowController alloc] initWithWindowNibName:#"iQueryWindow"];
[iQWController showWindow:sender];

Related

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.

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

NSWindow is nil after awakeFromNib

I have a nib file which has a bunch of views and custom objects in it. One of those objects is a custom controller object. In it's awakeFromNib method I want to access the window that is holding all of this stuff. I'm not sure how to get the window at this point. However, this custom object has an outlet to a view. I know that you can get the window from calling [nameOfView window] but for some reason, at this point, nil is being returned for the window, even though the view is non nil. At what point will the window be non nil?
As a side note, if I pass the window as a parameter to this custom object that is loaded from a nib file, do I have to worry about releasing/retaining it? How will memory management work with this NSWindow in my object that was loaded from a nib?
If I understood you correctly, you won’t be able to do this during the nib loading process:
Some controller (let’s call it the master controller) triggers the load of that nib file;
awakeFromNib is sent to the objects inside that nib file, including your custom controller object;
The master controller gets a reference to nameOfView (potentially via the custom controller) and adds it to the view hierarchy of a window.
Loading a nib file containing views doesn’t automatically add those views to the view hierarchy of a window, which is why [nameOfView window] returns nil your custom controller’s awakeFromNib implementation. Since in step 1 there’s a master controller who’s responsible for triggering the load of that nib file, I assume this master controller is the one responsible for adding views to a window. Have the master controller send a message to the custom controller when this happens so that your custom controller knows when nameOfView has been added to a window.

uitextfield delegate must be file's owner?

I've seen a few references (eg here) in response to folks having trouble getting the keyboard to dismiss in iPhone that say "double check that the delegate is attached to file's owner.
Is this necessarily true? Or just standard practice? Can't I have other objects in my nib, such as a subclass of UIViewController, and make connections to those as I like? I'd hate to have to route everything into the object that happens to be file owner.
That said, I'm having a difficult time getting the keyboard to disappear. I know it's connected to the delegate, because I can set break points and step through the code. I can see the [theTextField resignFirstResponder] get called (and return true), but the keyboard still won't go away.
Any other suggestions?
All of the controls in a particular view are intended to talk to the View Controller that owns the nib file. Even if you have, say, a UISlider that changes the value of a UITextField, this will be handled by a method in your UIViewController subclass that gets fired when the slider's value changes and updates the text in the text field. So 9 times out of 10 your UIViewController will be the nib file's owner.
Typically the text field delegate method you want to define is textFieldShouldReturn, calling resignFirstResponder on the text field, which it sounds like you've done.
Make sure that your outlet for theTextField is connected as well. It can be nil and the runtime will treat [nil resignFirstResponder] as a noop, not as an error.

viewDidLoad not being called by parent UITabBarController

Sample:
I've created a minimal set of files that highlight the issue here: http://uploads.omega.org.uk/Foo3.zip
If viewDidLoad/viewInitWithNibName are called, a message box is displayed. The message box is not displayed, therefore, the methods are not being called.
Details:
I have an application that is attempting to use a UITabBarController to switch between multiple views.
The views are linked up to the UITabBarController using interface builder (select the tab page, open Attributes (Option-1), and fill in the NIB Name field), and so are displayed "automatically" with no extra code-behind to make them appear.
Is it intended behaviour that views loaded like this do not have their viewDidLoad method executed? If not, how am I doing it wrong, and what do I need to change.
If it is intended behaviour, I can think of a few work-arounds, but any suggestions are appreciated:
Scrap the UITabBarController and implement the view switching myself (using initWithNibName and add/insert/push/Subview).
Call each of the children's viewDidLoad method manually in the UITabBarController's own viewDidLoad method.
Thank you in advance for any help you can offer.
OK, I've managed to solve this.
Linking the NIB to the TabBarController isn't enough - you also need to link the code beind file, it is not implicitly linked by the NIB even if you set the file owner correctly.
Open IB, and select the relevent page. Click in the middle to select the view controller. Enter the NIB name of the sub view, then go to the last page (option 4). In 'class identity', enter the name of the code-behind file for the sub-view NIB.
Everything will now work nicely.
I've uploaded a correct version of the sample code: http://uploads.omega.org.uk/Foo3-Correct.zip
You're not instantiating ImportedView anywhere in your project, so it's not calling either initXXX or viewDidAnything. If you put your alert code in -[FirstViewController viewDidLoad], it'll fire as expected.