NSWindow is nil after awakeFromNib - objective-c

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.

Related

Access NSWindow's Element via Child NSView/ViewController

Is it possible to access a NSWindowController's element from a child NSViewController?
Essentially I have a NSProgressIndicator that spins on the bottom corner of the NSWindow. This works because my WebView is in my NSWindowController instead of my NSViewController.
I want to break the logic apart now but I'm having trouble understanding how I'd access these elements from my View Controller.
Thanks!
You can't connect an outlet from one NIB to an object in another and the desire to do so indicates a problem with your design. If the view is so intimately connected to other things in the window, maybe it shouldn't be separated out into a different NIB.
A view should only go into a separate NIB when it makes sense as a self-contained unit. It should represent and manipulate its controller's representedObject and not much more. The controller might have a delegate that it informs about what's being done and asks to make customizing decisions.
Maybe you can continue to use a separate NIB if you adopt that sort of design. Perhaps the window will have a reference to some model object. It would configure the view controller to use that model object as its represented object. And perhaps the progress indicator would be bound to that same model object. Then, as the view manipulates its represented object, it would indirectly also affect the progress indicator.
Another option would be for the window controller to set itself as the delegate for the view controller and your view controller could invoke it at appropriate points to inform it of things going on in the view. Then the window controller could do whatever was appropriate to the progress indicator or other stuff in the window outside of the view. This hypothetical delegate is something you would have to add to the view controller class and you'd design its protocol.

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.

NSViewController and bindings

In my application I have a single nib file. The File's Owner is a NSViewController and insider there is just a vertical slider that I want to bind to a property in one of my classes. (I don't have any other nib files since it is a status bar application, so I don't have a window). The nib is loaded runtime to create a custom view for a NSMenuItem.
The problem is that I want to use an object controller to do the binding but I'm not sure what is the content of the object controller. How can I access from the nib to an arbitrary class in my project?
In the examples I have seen, usually the object controller uses the File's Owner to access the class (and the property for the binding) setting the Content Object binding to the File's Owner. But in my case from the File's Owner I do not have access to the class.
Any pointer?
Ok this works for me. It is enough subclassing NSViewController and sets the new subclass as the File's Owner. Now it is possible to use a Controller Object to bind through the File's Owner.
If you use XCode 4 you can Control-drag from the slider to the .h file (AppController.h?), and you will get the option to generate an outlet or an action. If you want to create an action, caused by sliding the slider, you should select action. The generated method will be called whenever the slider is changed. If you want the slider value to react to an event (or a changed instance variable in your program), set it to 'outlet'.
Hope that helps, let me know if you were really looking for something else :-)

awakeFromNib from nib1 got called when programmatically load nib2

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];

The relationship between UIViewController and UIView

I'm trying to understand how these two are connected. Every time you make a UIViewController does it also automatically come with its own UIView?
Also are these from Cocoa or Objective-C?
UIViewController is a Cocoa Touch class built for the purpose of managing UIViews. It expects to have a view hierarchy, but you don't "automatically" get a view (this is slightly inaccurate; see edit below). Usually you will obtain views by calling initWithNibName on your view controller.
There is some built-in magic in Interface Builder which knows that if File's Owner is a UIViewController (or subclass), there is a property called view. That's about it.
Once you have linked a view controller and a view, the view controller does a fair amount of work for you: it registers as a responder for view touch events, registers for device rotation notifications (and handles them automatically, if you wish), helps you take care of some of the details of animation, and handles low-memory conditions semi-automatically.
Edit: correction—if you don't call initWithNibName or set the view property manually, the view property getter will invoke loadView if view is nil. The default implementation of loadView will see if you've set nibBundle and nibName and attempt to load the view from there (which is why you don't have to call initWithNibName, most of the time), but if those properties aren't set, it will instantiate a UIView object with default values. So technically, yes, it does automatically come with its own UIView, but most of the time that's of little value.
UIViewController doesn't automatically come with a view. You have to make a view in the -loadView method. By default, this loads the view from the nib file you've specified. You can also override this method to make a custom view if you prefer not to use a nib.
Also, the view is not created right when the UIViewController is created. UIViewController uses a technique known as lazy-loading to defer the creation of a view until the view is actually accessed for the first time.