Programming model of NSViewController

Recently I have written a few posts about view controller. The view controller became the center of iPhone programming. So, whether you like the view controller or not, you should study how to use it.

One thing I didn’t understand at first was its term “NSViewController” and programming/UI modeling caused by the term. Because it is View Controller, it sounds like that it manages views. Let’s say that you have two views, one for system setting and the other for user-specific setting. Then it sounds like that the view controller manages the two views, and a programmer can ask the view controller to swap-in one view and swap out the other view. I already have used such mechanism with my own view handling code.

- (IBAction)selectSetting:(id)sender 
	NSView *mainview = [self mainView];
	NSArray *subviews = [mainview subviews];
	NSView *oldview = [subviews objectAtIndex:1];
	NSRect frameRect = NSMakeRect(20.0f, 29.0f, 555.0f, 400.0f);
        if( [[sender selectedItem] tag] == kSystemSettingTag )
		if( chosenViewTag != kSystemSettingTag)
			// switch the view to system setting view
			[mainview replaceSubview:[oldview retain] with:systemSettingView];
			[systemSettingView setFrame:frameRect];
			chosenViewTag = kSystemSettingTag;
			[systemSettingController check_IP_and_SANPath];
	else // User setting
		if( chosenViewTag != kUserSettingTag )
			// switch the view to user setting view
			[mainview replaceSubview:[oldview retain] with:userSettingView];
			[userSettingView setFrame:frameRect];
			chosenViewTag = kUserSettingTag;
			[userSettingController check_IP_and_SANPath];

The selectSetting:(id)sender method is invoked when a user choose whether to change some configuration for system setting or user specific setting from a pop-up menu.

It is very straight-forward and easy to understand. It can uses one NIB/XIB file in which multiple views are. What you need is IBOutlet or pointer to those views.

Probably if Apple wrote this mechanism, it would be possible to declare an internal array to handle those views and a view controller initializes the array with the pointers to those views.

However, Apple’s NSViewController doesn’t work like this.

The NSViewController requires you to prepare these.

1. Each xib/nib file which contains each each view. The owner object of the xib/nib file is your subclass of NSViewController. So, if you have two views named “Detail View” and “Table View”, you should have two xib/nib files. In each xib/nib file, you put a view for the detail view and a view for the table view, respectively. Also you will set their owner object to YourDetailViewController and YourTableViewController classes.

2. Therefore, you need to declare and define view controller classes for each view.

What is bad about this is that you declare and define almost identical classed multiple times although what they do is to load their views.

How to load is like this. (This is from KATI’s blog.)

- (void)windowDidLoad
	// Make table view controller
	// add views to the left side of the split view
	mTableViewController = [[TableViewController alloc] initWithNibName:@"TableView" bundle:nil];
	// get the left view from the split view
	NSView * aSplitViewLeftView = [[oMainSplitView subviews] objectAtIndex:0];
	// get the table view from its view controller
	NSView * aTableView = [mTableViewController view];
	// position the table view
	[aTableView setFrame:[aSplitViewLeftView bounds]];
	// set its autoresizing mask
	[aTableView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
	// add table view to the left subview of the split view
	[aSplitViewLeftView addSubview:aTableView];
	// Make detail view controller
	// add views to the right side of the split view
	mDetailViewController = [[DetailViewController alloc] initWithNibName:@"DetailView" bundle:nil];
	// get the left view from the split view
	NSView * aSplitViewRightView = [[oMainSplitView subviews] objectAtIndex:1];
	// get the table view from its view controller
	NSView * aDetailView = [mDetailViewController view];
	// position the table view
	[aDetailView setFrame:[aSplitViewRightView bounds]];
	// set its autoresizing mask
	[aDetailView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
	// add table view to the left subview of the split view
	[aSplitViewRightView addSubview:aDetailView];
	// patch the detail view into the responder chain
	NSResponder * aNextResponder = [self nextResponder];
	[self setNextResponder:mDetailViewController];
	[mDetailViewController setNextResponder:aNextResponder];

In this sample code, the code is in NSWindowController class.

It looks like that the NSViewController doesn’t do much for you to relieve small but tedious chores. Then, why do we care about the NSViewController? Probably right now it is only good for making view loading/replacing code consistent and unified for different apps and at different part of your codes. Or, after a while, there is a chance Apple Inc will add some more features to the NSViewController to make it really useful.

For the time being, would it be possible to make an NSViewController manages multiple views and swap-in/swap-out those? Unfortunately it doesn’t seem to be right out of the box.

However, there can be some possibility.
If you subclass the NSViewController, declare NSMutableArray or NSArray for maintaining views declared in a nib/xib file, and initialize it with pointer to views, then.. yes.

However, how to connect your views with the IB? If you write code without using IB for this part, yes, it could be done. But if you want to use the IB for this purpose.. Does anyone have some idea on this?

6 responses to this post.

  1. […] Programming help of NSViewController « JongAm’s blog […]


  2. I’m not sure whether I agree with you. Had Apple designed NSViewController in the way you propose in this blog entry, this would invariably lead to bloated and overly complex controllers. The current design is clean and relatively simple and allows you to build rather complex view hierarchies with a precise distribution of complexity


    • Posted by jongampark on February 7, 2012 at 8:25 AM

      Hmmm.. I don’t think idea around my approach is bloated. And I think it is more intuitive.
      However, anyway, NSViewController view is out there as it is now for many years and many got used to it already.
      So, my post is stale on the axis of time.


  3. Posted by Raj on March 17, 2012 at 2:39 AM

    I’m new to this but found this old post useful to get my head round views and controllers. It appears apple designed 1 view – 1 controller. It means you end up with loads of view controllers but maybe better organised. I think that for similar views you could use the same VC but change elements or sub views within it (in code)depending on the task. Not sure about a xib array for one VC.


    • Posted by jongampark on March 17, 2012 at 9:22 AM

      My post was written around when Apple introduced NSViewController.
      Different people can design things differently targeting different goals.
      Yes, from source code point of view, I think my approach is more reasonable, but Apple’s approach is turned out to provide easiness of handling views in a xib/nib file.
      Is it to use the controller to load/unload a view it controls.
      So, when we adopt Apple’s NSWindowController and NSViewController, there is one xib/nib per one controller. As a program grows in size, eventually this can help.

      What I felt a little odd at that time was that Apple people started to introduce something new with vague definition. People can have different point of view, so when they introduce a new concept, they have to define what is the overall scenario they think of. But from this NSViewController, it became somewhat blurry. And the context was also a little different from NSWindowController.
      It was the time Apple people started to be busy due to the popularity of iPhone OS ( now iOS ). So, it seems to me that they started to spend less time in house chores like writing sufficient documents cleaning up some bugs and taking care of Mac OS X. They were so busy to introduce new thins for iOS.

      But anyway, it’s great to hear that this helped you.


Leave a Reply

Please log in using one of these methods to post your comment: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: