macOS View Controllers Tutorial

In this macOS view controllers tutorial you’ll discover the wide range of functionality that is baked into vanilla view controllers, along with learning how you can create your own view controller subclasses to build up your app in an easy-to-understand manner. By Jean-Pierre Distler.

Leave a rating/review
Save for later
Share

When writing any code, it’s important to get clear separation of concerns — functionality should be split out into appropriate smaller classes. This helps keep code maintainable and easy to understand. Apple has designed the frameworks available on macOS around the Model-View-Controller design pattern, and as such has provided various controller objects that are responsible for managing the UI.

View controllers are responsible for hooking up the model layer to the view layer, and have an incredibly important role in the architecture of your macOS app.

In this macOS view controllers tutorial you’ll discover the wide range of functionality that is baked into vanilla view controllers, along with learning how you can create your own view controller subclasses to build up your app in an easy-to-understand manner. You’ll see how the life cycle methods allow you to hook into important events for the UI of your app, together with how view controllers compare with window controllers.

To follow this tutorial you’ll need the most recent version of macOS and Xcode installed on your mac. There’s no starter project — you’ll build a great app from scratch! You might like to read Gabriel Miro’s excellent tutorial on windows and window controllers before embarking upon this view controllers tutorial, but it’s not a requirement.

Enough introduction — let’s kick off with some theory!

Introducing View Controllers

A view controller is responsible for managing a view and its subviews. In macOS, view controllers are implemented as subclasses of NSViewController.

View controllers have been around for a while (Apple introduced them with OS X 10.5), but before OS X 10.10 they weren’t part of the responder chain. That means, for example, that if you had a button on a view controller’s view, the controller would not receive its events. After OS X 10.10, however, view controllers became very useful as building blocks for more complex user interfaces.

View controllers allow you to split the content of your window into logical units. The view controllers take care of those smaller units, while the window controller handles window-specific tasks like resizing or closing the window. This makes your code way easier to organize.

Another benefit is that view controllers are easy to reuse in other applications. If a File Browser with a hierarchical view on the left is controlled by a single view controller, you can use it in another application that needs a similar view. That’s time and energy saved, which you can now devote to drinking beer!

Window Controller or View Controller?

You may be wondering when to use only a window controller, and when to implement view controllers.

Prior to OS X 10.10 Yosemite, NSViewController was not a very useful class. It did not provide any of the view controller functionality you could expect — for instance, that found in UIViewController.

With the changes introduced since, like the view life cycle and the inclusion of the view controllers in the responder chain to receive events from its view, Apple is promoting the Model View Controller (MVC) pattern in the same way it’s currently doing with iOS Development. You should use view controllers to handle all the functionality of your views and subviews and the user interaction. Use window controllers to implement the functionality associated to the application windows, like setting up the root view controller, resizing, repositioning, setting the title, etc.

This approach will help in building a complex user interface by dividing the different parts of the UI into several view controllers and using them like building blocks to form the complete user interface.

View Controllers in Action

In this tutorial, you’ll write an application called RWStore that lets you select different books from raywenderlich.com store. Let’s get started!

Open Xcode and choose to create a new Xcode project, and select macOS/Application/Cocoa Application from the templates menu. Click Next.

Name your project RWStore. On the options screen, make sure that Swift is selected as Language and the Use Storyboards checkbox is checked. You don’t need Unit and UI Tests, so uncheck the corresponding checkboxes. Click Next and save your project.

Download the project resources. The zip file contains images for the books and a Products.plist file containing an array of dictionaries with the information for a product, like the name, description, and price. You will also find a source code file named Product.swift. This file contains the Product class, that reads the product information from the plist file. You’re going to add these to RWStore.

Select the Assets.xcassets folder in the Project Navigator and drop the downloaded images into the column containing the app icon.

Drag and drop Products.plist and Product.swift into the Project Navigator on the left. Make sure that Copy items if needed is checked.

Build and run the app. You should see the main window of your application.

window-empty

It’s empty now, but don’t worry — this is just the starting point.

Creating the User Interface

Open Main.storyboard, select View Controller Scene, and drag a pop-up button into the view. You’ll use this pop-up button to display the list of products.

add-popup

Set its position using auto layout. The pop-up button should occupy the full width of the view and stay pinned to the top, so with the pop-up selected, click the Add New Constraints button located in the bottom bar.

In the pop-up that appears, select the trailing constraint and set its value to Use Standard Value. Repeat for the top and leading constraints and click Add 3 Constraints.

To complete the UI, add a view to show the product details. Select a container view and drag it below the pop-up button.

add-container

A container view is a placeholder for another view and comes with its own View Controller.

Now we’ll set up the auto layout constraints for this view. Select the container view and click on the Add New Constraints button. Add top, bottom, trailing, and leading constraints with a value of 0. Click the Add 4 Constraints button.

Select the view of your view controller and click the Update Frames button at the left of row of constraints buttons. Your view should look like this:

FinishedVC

Now you’ll create an action that will be called when the button selection changes. Open the Assistant Editor (you can also use the keyboard shortcut Command-Option-Return) and make sure that ViewController.swift is open. Control-drag from the pop-up button into ViewController.swift and add an Action Connection. In the pop-up view, make sure the connection is an Action, the name is valueChanged, and the type is NSPopUpButton.

On the canvas, there is a new view controller connected to the container view with an embed segue. Your app will use a custom view controller, so you can delete the auto-generated one: select the view controller associated with the container view and press delete.

delete-viewcontroller

Contributors

Sarah Reichelt

Tech Editor

Michael Briscoe

Final Pass Editor and Team Lead

Over 300 content creators. Join our team.