Difference between NSWindowController Vs NSViewController - objective-c

I am coming from iOS background and starting to learn Cocoa. On iOS unless we have multiple targets for iPad and iPhone we usually have one Window and manage the screen using UIViewControllers. Where every new screen will most of the time will map to a UIViewController.
However on cocoa this seems to be the otherway around where a new screen/window is manage by NSWindow and it's subcomponents are managed by NSViewController. So if I have multiple window app I should have separate NSWindowController for each window.
Is this approach correct or am I having a misunderstanding ?

With iPhone SDK and Leopard SDK, they introduced view controllers, or NSViewController and UIViewController. As their names suggest what they do is to manage views
The view controllers are for managing views. Current trend in UI design is Single Window, Multiple View. What it means is that there is one Window and inside of it, different group of views designed for different purpose can be swapped in and out. So, the View Controllers handles these for programmers for well-established pattern.
Currently view controllers are very important for iPhone and iPod touch programming, because the platform is based on Single-Window and Multiple View model. However, it doesn’t seem to me that using view controller is very popular for Mac.
how about the window controller like NSWindowController? Its counterpart, UIWindowController doesn’t exist for the iPhone and iPod touch environment, because there is only one window for those environment.
Unlike view controllers, the NSWindowController is for document based programs. Well, document based program can use multiple window. So, it is reasonable to think that NSWindowController is for document based programs as Apple’s document says.

I also come from iOS and started coding Mac apps a while ago, learning mostly from Apple's documentation.
My impression is that on the desktop, you almost never need NSViewControllers (one big exception would be a window with tabs and multiple views, like the GarageBand welcome screen).
Most of the time you have one NSWindowController per window. Learn first the relation between NSWindow and NSWindowController (and NSDocument, if you are making a document-based app).
Once you got that right, start experimenting with NSViewController.
UPDATE: It seems that since the introduction of storyboards for mac apps too, Apple expects that most of the view presentation logic should be migrated from the older NSWindowController to the newer NSViewController, more in line with how an iOS app is structured. I am not very knowledgeable on exactly where to draw the line, or what kind of code should remain in the window controller (or whether it still needs to be subclassed at all).

A Window Controller creates a traditional window and has all the traditional APIs.
A View Controller can also be shown outside of another view. It then gets a window frame but does not support the full traditional Window Controller API.
In addition to custom, modal, and show, a View Controller can also be presented in the modes sheet and popover.
So, View Controller has more presentation options and a more streamlined API but probably a few limitations in cases that are covered by the traditional Window Controller.

Related

Cocoa app design recommendation

I have a Mac app that needs to be based on multiple modules. That is, a single window with multiple views, and the default view with a menu. That menu should open one module on the default window and then if I select another module, the contents of the window should change with another view. Those views also have different states, so I made multiple views for each module.
In a nutshell, my app is a single AppDelegate.h/.m, a single xib file, with one NSWindow object and multiple NSView views. Those views have different states, so I load different other related NSViews.
To load a view, I use [window setContentView:viewNameView]; which I know that causes the old NSView to lose state, so I need to keep them all in memory for each module.
Is this the right approach?
Thank you!
You don't describe how and where you want the menu but a widely used method is to have a sourcelist on the left and the content on the right. You see this everywhere including Apples own apps.
If you create a sourcelist on the left of your window and place an NSBox on the right side.
Set up the sourcelist (NSOutlineView) to react to - outlineViewSelectionDidChange: which is an NSOutlineView delegate method.
Here you can check the identifier on the selected item in the menu and set the content view for the NSBox accordingly with - setContentView:
Here's a great introduction to using NSOutlineViews for anyone interested.
Edit: Depending on how many views you have it might be easier to have an NSTabView (in tabless mode) and just switch tabs in the - outlineViewSelectionDidChange: method. This is also widely used and the user won't see the difference.
You will want to look up NSWindowController for managing your window and xib, and NSViewController for managing views. The app delegate shouldn't do much (in fact you probably could remove the header file and merge it with .m).
Some references to look at:
https://www.mikeash.com/pyblog/friday-qa-2013-04-05-windows-and-window-controllers.html
https://developer.apple.com/library/mac/samplecode/ViewController/Introduction/Intro.html
Yes that will work. What you may end up needing as well, is a custom Navigation Controller. Unfortunately Cocoa doesn't have an NSNavigationController, so you'll have to write something on your own. But basically yeah what you'll do is swap out the contentView with the next view you want to display-- and keep a stack of views you've navigated to so you can support going back (or you could use a dictionary to add transition keys to create strongly linked transitions)
Here's an good example somebody posted in a previous thread-- if you just search for Cocoa Mac Navigation Controller you should find some helpful results :)
Mac OS X Cocoa multiview application navigation
Another thing that you may want to keep in mind, which came up for me, is if your views are of different sizes. If they are, and you are using auto-layout, you will need to update the constraints to resize the window appropriately as views are swapped out

Programming a Universal App in iOS

When I am programming a universal app, lets say I have an IBAction like so:
(IBAction)magicCode:(id)sender {
textField1.text = "TEST";
}
Do I need to create a new IBAction for each view (iPad and iPhone). I can't have textField1 twice in header file, so I am just wondering how everyone else does this. Do I need to put a textfield in the iPhone app with a different name than the one in the iPad app? Or is there some other way everyone else is doing this?
Do I need to create a new IBAction for each view (iPad and iPhone).
First, actions are typically included in view controllers, not views. I think that's probably what you meant, but I point out the difference because I've seen a lot of people get confused on this point.
When you're creating a universal app, i.e. a single app that adapts its UI to the device (iPad or iPhone/iPod Touch) on which it's running, a common strategy is to provide different view layouts that make the best use of the available screen size, but to use the same view controllers. So, for example, say you have an app with a master/detail interface. On small devices, you'd present the master part of the interface first, and when the user chooses something you'd display the detail part of the interface. On an iPad, with it's larger screen, you'd display both master and detail interfaces simultaneously in a split view. Comparing the two, the views are likely to be different, and the way the view controllers are presented is different, but the view controllers themselves should stay the same. This is a good thing, since much of the work of creating an app goes into creating the view controllers.
If your app is similar to what I've described (or if you can make it similar), then no, you don't need separate actions for iPad and iPhone because you'll be using the same view controllers in both cases. There may be times, though, when the behavior of the app on the two different devices is different enough that it makes sense to have iPad-specific and iPhone-specific view controllers. You might still be able to use the same actions by deriving each of those from a common parent class that contains the actions. If not, you'll need to have each class implement its own actions.
No, you can have the same IBAction and IBOutlet in a UIViewController dealing with textfields in two different Nibs (one for iPhone and one for iPad). That's the whole point of separation between View Controller and Views in MVC architecture.
Just use the same UIViewController as File's Owner in both the Nibs and make all the appropriate IBOutlet and IBAction connections and everything will work.

How Can I Display the Map At Will?

I’ve borrowed the Whereami code found in The Big Nerd Ranch iOS book and used it in the app I’m writing. My app determines the user's location and displays it in a map in the app delegate, just like Whereami app in the book does. The UIWindow is made visible and displays the map correctly. From this point on, the code is my own.
My app allocates a UINavigationController, sets the root view controller, and proceeds to allow the user to view other view controllers and perform other methods after navigating to them.
At some point, a view controller contains a button labeled “MAP” that, when pressed, should display the map showing the user’s current location.
How can I get the app to display the UIWindow that is in the AppDelegate.m? I assume the app delegate is continuing to determine the user’s location, and I want the user to have the ability to display the map at will.
My current code allocates a MapViewController when the “MAP” button is pressed, but I can’t figure out how to get the UIWindow which is in the AppDelegate.m to display.
I’m thinking I should be able to do it by having a pointer to the UIWindow in the MapViewController. Is this the right approach? Do I need anything else? I'm using Xcode 4.0.2, Snow Leopard, and testing on an iOS 4 device. I'm new at this, and I don't want to get confused by upgrading to Lion, a higher Xcode, or iOS 5 yet.
Consider using presentModalViewController:animated: (it's a method on all instances of UIViewController and its subclasses). There are a variety of transition styles you can use, like a flip or a fade.
On iOS you very rarely work with UIWindow objects. You pretty much set one up when your app launches and you leave it alone. Everything is done with UIView instances or the UIViewController instances that manage them.

Split NSTabView across multiple NSViewControllers and XIBs

I'm just getting into desktop Cocoa development (I have experience with iOS development). If this question seems basic, forgive me.
That being said, I'm dealing with a large program with lots of calculations and functionality to deal with. There are almost a dozen views, organized with an NSTabView. Rather than dumping everything into one monstrosity of a class and creating a XIB file that brings my system to its knees (Xcode apparently isn't that efficient…who knew? :P). I'd like for each tab to be its own NSViewController with accompanying XIB; as such, I'd like to load each tab's view from the corresponding XIB.
I'm thinking of this in terms of UITabBarController, but this doesn't seem to work (there isn't an NSTabViewController as far as I could find). I'm not sure how to do this (or even if it's possible—but I can't be the only one with this issue?), and I'd appreciate any assistance. Thanks!
Update: I tried assigning the controller's view to the tab's view, but quickly realized that wouldn't get me anywhere. Is it worth creating an NSTabViewController from scratch, or is there a solution out there?
Cocoa development on the desktop has some major differences compared to iOS development. One of them is the use of view controllers - they aren't strictly necessary - and when you use them you can just stick to a generic NSViewController regardless of what kind of view it contains. All of the methods you need to control the tab view are in the NSTabView class - not the controller.
Having said that, putting 12 views in to a tabview sounds like a painful way to interact with a program. Have you thought about a source-detail type setup (think itunes or mail with their sidebars - each entry in the sidebar corresponds to a different view)?
I've ditched the tab bar, and as per sosborn's suggestion, I have used a split view—or rather I've put a table view on the side, and a custom view taking up most of the screen. Then, in my AppDelegate, I have individual controllers as ivars (I need individual controllers because there are a lot of calculations involved, and I don't want to have a monster class handling them all). They'll be lazily loaded, and the view will be assigned to the current controller's view as necessary.

Should one use UIViewController in scenarios without UINavigationController?

Summary
From a conceptual point of view, should one be working with UIViewController subclasses and their Nibs, even if you're not using the UINavigationController?
Scenario
The application I'm trying to develop has no UINavigationController. I'm mostly looking at elements in one particular UIScrollView implementation, and if there's at all a 'next level of navigation', it merely alters the appearance of a small element to show more details. The detail views of the elements (different elements spawn different views) are laid out in Interface Builder, for which I opted to create new UIViewController subclasses with corresponding XIB files.
Doubt
While exploring the different ways I could have these instances animate into view, I come across a lot of solutions using the UINavigationController. The UIViewController itself already seems to be geared towards the synergy. There's a self.navigationController, and lot's of examples online of how to push and pop with and without animation.
Question
So what I'm wondering right now is "did I do the right thing?" Googling an answer to that question only brought me to more specific implementation examples, so I decided to post this.
Should I have restrained myself in using XCode's "new file" template for UIViewController subclasses with XIB? Or should I have implemented a UINavigationController in my app, even if there's no screenfulls of navigation going on?
I'd be much obliged for enlightenment.
Cheers,
Eric-Paul.
UIViewController is a useful tool. It offers memory management things, anchor points for interface rotation and lots more. If needed, they can be pushed to a navigation controller (if not now, maybe later), could be a page of a tab bar controller, or behave well in popovers on iPad.
They come cheap and I don't see a reason not to use them. And your code needs to go somewhere anyway. Don't flood the application delegate or the view.