How to manipulate the underlying Text View within a Window? - xcode

This is a document-based app. I want to manipulate the underlying text view within my window. I set it up as follows:
So I also created an outlet to my document class to manipulate it.
#property (strong) IBOutlet NSTextView *textView;
Though it doesn't respond to any methods I call on it. Just to test, i want the textview to load with inserted text but the textview doesn't respond at all.
self.textView.string = #"Hello world";
What am I doing wrong?

You cannot refer to the text view initialized from the nib until the nib has loaded and the text view has been created. At that point, windowControllerDidLoadNib: is called, and the nib objects are instantiated. Until then, the textView outlet is nil. So I'm guessing that that's the problem.

Related

OS X second window won't stay open

I want to open a second window to act as a content editor for some of the fields in the main window of my app. I created a custom NSWindowController (called ItemEditor) with its own nib.
I open the new window with this code:
ItemEditor *editor = [[ItemEditor alloc] initWithWindowNibName:#"ItemEditor"];
[editor showWindow:nil];
[editor.window makeKeyAndOrderFront:nil];
The new window appears for an instant and then immediately disappears. Both the initWithWindow: and windowDidLoad of ItemEditor are called, but windowWillClose: isn't.
Can anyone tell me what's going on here? I'm stumped.
What's happening is that you're using ARC... and nothing is holding onto your "editor" object after it's created. That's why it's disappearing as soon as it's being created.
You need to make "editor" a "strong" property in your parent window controller.
In other words, declare it like this in the parent view controller's .h file:
#property (strong) ItemEditor *editor;
And replace the first line of your code snippet above with this:
self.editor = [[ItemEditor alloc] initWithWindowNibName:#"ItemEditor"];

Receive window notifications

I have an NSWindow set up in Interface Builder. I have set the class of File's Owner to my NSWindowController and linked the window property of the controller to my NSWindow.
My controller implements NSWindowDelegate.
Now, in my controller, I have added the following:
- (void)windowDidLoad
{
[super windowDidLoad];
[self.window setDelegate:self];
}
- (void)windowDidBecomeMain:(NSNotification *)notification
{
NSLog(#"Did become main.");
}
Still, -windowDidBecomeMain: isn't called. Does anyone know why this is?
EDIT:
Trying to show a window from AppDelegate on launch. The main nib (declared in Info.plist) contains a menu item only which is linked to the AppDelegate. In the application delegate, I show an icon on the status bar and when this icon is clicked, I display the menu from the main nib.
In the application delegate, I also want to display a window which should have a window controller assigned to take care of the logic.
I believe that when this works, I will receive my window notifications.
Now, the following code doesn't show the window and I can't figure out why.
DemoWindowController *dwc = [[DemoWindowController alloc] initWithWindowNibName:#"DemoWindowController"];
[dwc showWindow:self];
Note that self is the application delegate.
I suspect your problem is due to the fact that your window controller is not actually the object that is the nibs file owner.
When you change the class in interface builder you are telling it what outlets and actions are available (which is why you are able to drag to the window outlet) but you are still responsible for passing in this object yourself.
In the case of a non-document based application, you will have a main method which calls NSApplicationMain. What this does is basically look up and load the window nib that is specified in your info.plist file and pass the current NSApplication instance to this nib as the files owner (so even though you changed the class type to NSWindowController, the object being passed in is actually of type NSApplication).
The easiest way to fix your problem is to get rid of your window controller for now (as it isn't actually doing anything yet).
You should implement the -windowDidBecomeMain: method in your app delegate. Then Ctrl+drag from your window to your appDelegate to set it as the delegate of the window to get your notifications.
Update
To answer your question regarding the WindowController beware of the following two issues:
You are creating your window controller variable (dwc) in your applicationDidFinishLaunching: method. This is released the moment you leave the method taking your window with it. Create an instance variable to hold onto the window controller instead.
Ensure that your second window nib has its file owner set to NSWindowController (or your window controller type) and that its window outlet is connected to the window in the nib file.
Your window should now display.

Can I use NSViewController to provide a reusable NSTableView with defined columns and data?

I'm fairly new to Xcode and Cocoa development, so please excuse me if I use the wrong terminology.
I have a window which has an NSTableView bound to a NSArrayController. The NSTableView has some predefined columns and the NSArrayController is populated with data when my window is loaded.
This all works fine, but I now need to re-use the functionality in a number of other windows.
After much reading I think and NSViewController is what I need, to provide an object that I can re-use in different windows in multiple .xib.
So what I have done is created a new NSViewController sub class in Xcode which also created a new xib for that controller.
The xib contains a custom view, where I have placed my NSTableView.
#interface KeyViewController : NSViewController
#property (weak) IBOutlet NSTableView *keyTable;
#end
The files owner class is set to the KeyViewController, and the view outlet is set to the files owner.
I then placed a ViewController object into the original window and hooked up the view to a new custom view in the window
I then set the nib name for the ViewController in its properties.
The new view never gets displayed and the view controller initWithNibName never gets called.
Am I missing something vital or missing the plot completely. Should you be able to do this just with interface builder or do I need to alloc and init the view in code?
If I do have to do it in code, whats the purpose of the ViewController object in IB and the Nib Name property for it?
Thanks..

NSWindowController object linkage in Interface builder

I created a NSWindow xib file that I want to open on click of a button in another window.
Now, to control the behavior of the NSWindow, I dragged an object from Library in xib and changed it to subclass of NSWindowController (i.e. ListingWindowController) that I defined in XCode.
Similarly I also created a subclass of NSViewController (i.e. ListingViewController) to manage the NSView inside the NSWindow. To do this, I dragged NSViewController from Library in xib and changed its class to ListingViewController.
#class ListingViewController;
#interface ListingWindowController : NSWindowController {
IBOutlet ListingViewController *listingVC;
}
#property (nonatomic, retain) IBOutlet ListingViewController *listingVC;
#end
I connected window and listingVC of my window controller in IB.
Now to invoke this window on click of a button in my launch (first) window, I create the window controller using initWithWindowNibName like this..
- (IBAction) pushConnect:(id)sender {
NSLog(#"Connect pushed.");
if (wc == nil) {
wc = [[ListingWindowController alloc] initWithWindowNibName:#"ListingWindow" owner:self];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(closeWindow:) name:NSWindowWillCloseNotification object:nil];
[wc showWindow:sender];
}
}
The problem is that despite all the bindings done in IB for the view controllers of upcoming window/view, the window and listingVC comes out to be (null), (null) even after the new window has loaded (below code).
- (void)windowDidLoad {
[super windowDidLoad];
NSLog(#"windowDidLoad = %#, %#", self.window, self.listingVC);
}
Please help why the connections are not working. I'm banging my head against this problem for quite a while now.
PS: I'm coming from iOS programming background. So, I'm assuming the Mac's window/view controller behave similar to iOS UIViewControllers.
TIA..
Note that:
wc = [[ListingWindowController alloc] initWithWindowNibName:#"ListingWindow" owner:self];
means that self (it’s not clear what self is from your question) is the owner of ListingWindow.nib. This means that self is the one who keeps outlets to objects in that nib file, and self is responsible for releasing the top-level objects in the nib file. This also means that you’re creating an instance of ListingWindowController in your code and another instance inside your nib file since you’ve dragged an object of class ListingWindowController onto the nib file.
This is not how it’s supposed to be.
In the vast majority of cases, a window (view) controller loads a nib file and becomes its owner. It has a window (view) outlet that must be linked to a top-level window (view) in the nib file. Being the nib file’s owner, it must have been created before the nib file is loaded.
In order to achieve this for your window controller, you need to set the file’s owner class to ListingWindowController. You must not drag an object cube and instantiate the window controller inside the nib file. The window controller is the owner of the nib file, so it must exist before the nib file is loaded. You must also link the window outlet in file’s owner to the top-level window object in the nib file so that the window controller is aware of what window it should manage.
Having done that, use:
wc = [[ListingWindowController alloc] initWithWindowNibName:#"ListingWindow"];
instead of:
wc = [[ListingWindowController alloc] initWithWindowNibName:#"ListingWindow" owner:self];
since wc is supposed to be the owner of the nib file.
View controllers work similarly. They’re created before loading the nib file, are responsible for loading a nib file that contains a view as a top-level object, are that nib file’s owner, and have a view outlet that must be linked to that top-level view.
It’s not clear from your question whether you have a separate nib file for the view. If you don’t, then using a subclass of NSViewController is not needed at all — you could use a subclass of NSObject instead. If you insist on using NSViewController to manage a view that’s not loaded from a separate nib file, then you should override -loadView so that you get a reference to the view by some means other than loading it from a nib file, and sending it -setView: so that it is aware of the view it’s supposed to be managing.
Recommended reading: Nib Files in the Resource Programming Guide, NSWindowController class reference, NSViewController class reference.

Reference to subclassed NSWindowController returns its document - is this correct?

I am new to document-based applications and hence I may have missed something fundamental. I have written a document based application which uses a subclassed NSWindowController for the interface and a subclassed NSDocument for the model. Per the documentation I initialise the windowController in makeWindowControllers and load its xib. In interface builder, the xib has my windowController subclass set as File's Owner. Among the views in the window, I have a subclass of NSOutlineView and the NSOutlineView datasource and delegate are also refenced in the nib and connected to the windowController via IBOutlets.
According to the documentation, I should be able to access the document from the OutlineView datasource via [windowController document]. However, referencing the windowController (via IBOutlet) from the OutlineView datasource gives me the document instead!
This has lead to some rather ugly code in the OutlineView datasoure (which is a subclass of NSObject in the windowController's xib) to get hold of the document, eg:
-(MyDocument *)myDocument {
MyDocument *theDocument = (MyDocument *)myWindowController;
return theDocument;
}
Where the IBOutlet in the header file references myWindowController as:
IBOutlet MyWindowController *myWindowController
In brief - why does an IBOutlet connected to the windowController get me the document directly instead in this situation? The above code works but seems as if it shouldn't.
Edit: clarification
Okay, I worked out the answer to this one - don't accidentally set the File's Owner of the xib to the NSDocument instead of the windowController in another part of your code and forget that you did it! This overrides the File's Owner that you previously set in the xib.

Resources