macOS Controls Tutorial: Part 1/2

Ernesto García
Get started with macOS controls!

Get started with macOS controls!

Update Note: Updated for Xcode 8.2 / Swift 3 by Ernesto García. Previous update to Xcode 6.3 / Swift 1.2 by Michael Briscoe. Original post by Ernesto García.

If you’re an iOS developer and you’re interested in learning about Mac development, you’re in luck – with your iOS skills, you’ll find it quite easy to learn!

Many of the Cocoa classes and design patterns you know and love like strings, dictionaries and delegates have direct equivalents in Mac development. You’ll feel right at home!

However, one big difference with macOS development are there are different controls. Gone are UIButton and UITextField – instead there are similar (but slightly different) variants.

This tutorial will introduce you to some of the more common macOS controls of the user interface — the foundation upon which most Mac apps are built. You’ll learn about these controls, as well as the methods and properties you’ll need to understand in order to get up and running as a developer! :]

In this tutorial, you’ll be creating a simple Mac application like the popular game Mad Libs. Mad Libs is a word game where you can insert different words in a block of text in order to create a story — which often has hilarious results!

Once you’ve completed both parts of this tutorial, you’ll have a fundamental understanding of the following macOS controls:

  • Labels and Text Fields
  • Combo Boxes
  • Popup Buttons
  • Text Views
  • Sliders
  • Date Pickers
  • Buttons
  • Radio Buttons
  • Check Buttons
  • Image Views
Note: Following this tutorial requires some knowledge of macOS development. If this is the first time you’re developing for macOS, you may want to go through our macOS Development Tutorial for Beginners series to learn the basics.

The best way to learn any new programming platform is to dive right in and get started — so without further ado, here’s your introduction to macOS Controls! :]

Getting Started with macOS Controls

Open Xcode, and choose File/New/Project. In the Choose a template dialog, select macOS/Application/Cocoa, which is the template you use to create an app with a GUI on macOS. Then click Next.

macos-template

In the next screen, type MadLibs as the product name, and enter a unique Organization name and identifier. Make sure that Use Storyboards is checked and Swift is the selected language.

macos-projectname

Click Next and choose the location where you’d like to save your new project. Click Create.

Open Main.storyboard. Xcode has created for you the basic skeleton of a macOS app: a Window controller and a content View controller.

Select the window in the Window Controller Scene and open the Attributes Inspector. Change the window Title to MadLibs.

MadLibsWindowTitle

A macOS app usually has a resizable window and its content has to adapt to the window size. The best tool for that is Auto Layout. To add Auto Layout to all the controls in this tutorial would create a major distraction; we want you to focus strictly on the macOS controls.

Accordingly, only the default autoresizing is applied, which means that all controls will maintain a fixed position and size, regardless of any window resizing the user performs — including the possibility that some of the controls fully or partially will be out of the window’s visible rectangle.

Note: If you want to learn more about Auto Layout and how to use it in your macOS apps, you can follow our macOS Development Tutorial for Beginners, Part 3.

During the tutorial, you’ll need to add some macOS controls to this view, and the default height may not be enough to fit them all. If you need to resize it, drag down the bottom edge of the content view, or set the view’s Height property in the Size Inspector.

drag-resize

Build and run.

empty-window

You’ve built a working application — without any coding at all. The window is empty right now, but you’re going to fill it up with some macOS controls and make it look great! :]

Now that the basic framework has been laid down, you can move on to the main focus of this tutorial — adding macOS controls to your app.

Each of the remaining steps in this tutorial will focus on a single, different control. You’ll learn the basics of each control and how to use each one in the MadLibs app to try it out.

NSControl – The Building Block of MacOS Controls

NSControl is the foundation upon which all other macOS controls are built. NSControl provides three features which are pretty fundamental for user interface elements: drawing on the screen, responding to user events, and sending action messages.

As NSControl is an abstract superclass, it’s entirely possible that you’ll never need to use it directly within your own apps unless you want to create your own custom macOS controls. All of the common controls are descendants of NSControl, and therefore inherit the properties and methods defined in that.

The most common methods used for a control are getting and setting its value, as well as enabling or disabling the control itself. Have a look at the details behind these methods below:

Set the Value of macOS Controls

If you need to display information you’ll usually change the control’s value. Depending on your needs, the value can be a string, a number or even an object. In most circumstances, you’ll use a value which matches the type of information being displayed, but NSControl allows you to go beyond this and set several different value types!

The methods for getting and setting a control’s value are:

// getting & setting a string
let myString = myControl.stringValue
myControl.stringValue = myString

// getting & setting an integer
let myInteger = myControl.integerValue
myControl.integerValue = myInteger

// getting & setting a float
let myFloat = myControl.floatValue
myControl.floatValue = myFloat

// getting & setting a double
let myDouble = myControl.doubleValue
myControl.doubleValue = myDouble

// getting & setting an object
let myObject: Any? = myControl.objectValue
myControl.objectValue = myObject

You can see how the different setters and getters fit with the type-safety of Swift.

Enable & Disable macOS Controls

Enabling or disabling macOS controls based on the state of an app is a very common UI task. When a control is disabled, it will not respond to mouse and keyboard events, and will usually update its graphical representation to provide some visual cues that it is disabled, such as drawing itself in a lighter “greyed out” color.

The methods for enabling and disabling a control are:

// disable a control
myControl.isEnabled = false

// enable a control
myControl.isEnabled = true

// get a control's enabled state
let isEnabled = myControl.isEnabled

Okay, that seems pretty easy — and the great thing is that these methods are common to all macOS controls. They’ll all work the same way for any control you use in your UI.

Now it’s time to take a look at the more common macOS Controls.

Field of Dreams – NSTextField

One of the most common controls in any UI is a field that can be used to display or edit text. The control responsible for this functionality in macOS is NSTextField.

NSTextField is used for both displaying and editing text. You’ll notice this differs from iOS, where UILabel is used to display fixed text, and UITextField for editable text. In macOS these controls are combined into one, and its behavior changes according to the value of its isEditable property.

If you want a text field to be a label, you simply set its isEditable property to false. To make it behave like a text field — yup, you simply set isEditable to true! You can change this property programmatically or from Interface Builder.

To make your coding life just a little easier, Interface Builder actually provides several pre-configured macOS controls to display and edit text which are all based on NSTextField. These pre-configured macOS controls can be found in the Object Library:

textfields-catalog

So now that you’ve learned the basics about NSTextField, you can add it to your Mad Libs application! :]

Living in the Past — A Past Tense Verb

You will add various macOS controls to the MadLibs app, which will allow you to blindly construct a funny sentence. Once you’ve finished, you will combine all the different parts and display the result, hopefully with some comedic value. The more creative the you are, the more fun they’ll be!

The first control you’ll add is a text field where you can enter a verb to add it to the sentence, as well as a label that informs what the text field is for.

Open Main.storyboard. Locate the Label control in the Object Library and drag it onto the view in the View Controller Scene. Double-click the label to edit the default text, and change it to Past Tense Verb:.

Next, locate the Text Field control and drag it onto the view, placing it to the right of the label, like this:

drag-label

Now, you’ll create an outlet to the text field in the view controller. While the Main.storyboard is open, go to the Assistant editor. Make sure that ViewController.swift is selected and Ctrl-Drag from the text field in the storyboard into the pane containing ViewController.swift, and release the mouse just below the class definition to create a new property:

textoutlet-1

In the popup window that appears, name the Outlet pastTenseVerbTextField, and click Connect.

textoutlet-popup

And that’s it! You now have an NSTextField property in your view controller that is connected to the text field in the main window.

You know, it would be great to display some default text when the app launches to give an idea of what to put in the field. Since everyone loves to eat, and food related Mad Libs are always the most entertaining, the word ate would be a tasty choice here.

A good place to put this is inside viewDidLoad(). Now, simply set the stringValue property you learned about earlier.

Open ViewController.swift and add the following code to the end of viewDidLoad():

// Sets the default text for the pastTenseVerbTextField property
pastTenseVerbTextField.stringValue = "ate"

Build and run.

buildrun-textfield

Okay, that takes care of a single input with a default value. But what if you want to provide a list of values to select from?

Combo Boxes to the rescue!

The Value Combo – NSComboBox

A combo box is interesting — and quite handy — as it allows the user to choose one value from an array of options, as well as enter their own text.

It looks similar to a text field in which the user can type freely, but it also contains a button that allows the user to display a list of selectable items. You can find a solid example of this in macOS’s Date & Time preferences panel:

date-sshot

Here, the user can select from a predefined list, or enter their own server name, if they wish.

The macOS control responsible for this is NSComboBox.

NSComboBox has two distinct components: the text field where you can type, and the list of options which appear when the embedded button is clicked. You can control the data in both parts separately.

To get or set the value in the text field, simply use the stringValue property covered earlier. Hooray for keeping things simple and consistent! :]

Providing options for the list is a little more involved, but still relatively straightforward. You can call methods directly on the control to add elements in a manner similar to mutable Array, or you can use a data source — anyone with experience on iOS programming and UITableViewDataSource will feel right at home!

Note: If you are not familiar with the concept of Data Sources, you can learn about it in Apple’s Delegates and Data Sources documentation.

Method 1 – Calling Methods Directly On The Control

NSComboBox contains an internal list of items, and exposes several methods that allow you to manipulate this list, as follows:

// Add an object to the list
myComboBox.addItem(withObjectValue: anObject)

// Add an array of objects to the list
myComboBox.addItems(withObjectValues: [objectOne, objectTwo, objectThree])

// Remove all objects from the list
myComboBox.removeAllItems()

// Remove an object from the list at a specific index
myComboBox.removeItem(at: 2)

// Get the index of the currently selected object
let selectedIndex = myComboBox.indexOfSelectedItem

// Select an object at a specific index
myComboBox.selectItem(at: 1)

That’s relatively straightforward, but what if you don’t want your options hardcoded in the app — such as a dynamic list that is stored outside of the app? That’s when using a datasource comes in really handy! :]

Method 2 – Using A Data Source

When using a data source the combo box will query the data source for the items it needs to display as well, as any necessary metadata, such as the number of items in the list. To obtain this information, you’ll need to implement the NSComboBoxDataSource protocol in one of your classes, normally the View Controller hosting the control. From there, it’s a two-step process to configure the combo box to use the data source.

First, set the control’s usesDataSource property to true. Then set the control’s dataSource property, passing an instance of the class implementing the protocol; when the class implementing the data source is the hosting View Controller a good place for this setup is viewDidLoad(), and then you set the dataSource property to self as shown below:

class ViewController: NSViewController, NSComboBoxDataSource {
.....
  override func viewDidLoad() {
    super.viewDidLoad()
    myComboBox.usesDataSource = true
    myComboBox.dataSource = self
  }
.....
}

Note: The order of the instructions in the code above is important. An attempt to set the dataSource property when useDataSource is false (which is the default) will fail and your data source will not be used.

In order to conform to the protocol, you’ll need to implement the following two methods from the data source protocol:

// Returns the number of items that the data source manages for the combo box
func numberOfItems(in comboBox: NSComboBox) -> Int {
  // anArray is an Array variable containing the objects
  return anArray.count
}
    
// Returns the object that corresponds to the item at the specified index in the combo box
func comboBox(_ comboBox: NSComboBox, objectValueForItemAt index: Int) -> Any? {
  return anArray[index]
}

Finally, whenever your data source changes, to update the control, just call reloadData() on the combo box.

Which Method To Use?

If your list of items is relatively small and you don’t expect it to change that often, adding items once to the internal list is probably the best choice. But if your list of items is large or dynamic, it can often be more efficient to handle it yourself using a data source. For this tutorial you’ll be using method 1.

Now that you’ve covered the fundamentals of the combo box, move on to implement one in your app! :]

The Singles Bar — A Singular Noun

In this section you’ll add a combo box to enter a singular noun. You can either choose from the list or enter your own.

First, add a label that describes what the control is for.

Open Main.storyboard. Locate the Label control in the the Object Library palette, and drag it onto the content view. Change its alignment to Right and its title to Singular Noun:.

Note: Alternatively as a shortcut, hold down the Option key and drag an existing label to duplicate it. This is handy so you can keep the same size and properties of an existing label.

Locate the Combo Box control and drag it onto the content view, placing it to the right of the label.

addcombo

Now you need to add an NSComboBox outlet to the view controller. Use the same technique you used for the text field: select the Assistant Editor (making sure ViewController.swift is selected) and Ctrl-Drag the combo box to the ViewController class just below the NSTextField:

combo-outletIn the popup window that appears, name the outlet singularNounCombo.

combo-outlet-2

Now the NSComboBox property is connected to the combo box control. Next you are going to add some data to populate the list.

Open ViewController.swift and add this code under the outlets:

fileprivate let singularNouns = ["dog", "muppet", "ninja", "pirate", "dev" ]

Now, add the following code at the end of viewDidLoad():

// Setup the combo box with singular nouns
singularNounCombo.removeAllItems()
singularNounCombo.addItems(withObjectValues: singularNouns)
singularNounCombo.selectItem(at: singularNouns.count-1)

The first line removes any items added by default. Next, it adds the names from singularNouns to the combo box using addItems(). Then, it selects the last item of the list.

Build and run the application to see your combo box in action!

buildrun-combo

Great — it looks as though everything is working just right. If you click on the combo box, you can then view and select any of the other items.

Now, what if you wanted to present a list of choices, but not allow you to enter your own? Read on, there’s a control for that as well!

Pop Goes the Weasel — NSPopupButton

The pop up button allows the user to choose from an array of options, but without giving the user the option of entering their own value in the control. The macOS control responsible for this is NSPopupButton.

Pop up buttons are incredibly common in macOS, and you can find them in almost every application — including the one that you’re using right now: Xcode! :] You’re using the pop up button to set many of the properties on the macOS controls you’re using in this tutorial, as in the screenshot below:

popup-example

Filling the Spaces — Adding Items To Pop Up Buttons

As you might expect, adding items to NSPopUpButton is similar to adding items to NSComboBox — except that NSPopUpButton doesn’t support using a data source for the content of the control. NSPopUpButton maintains an internal list of items and exposes several methods to manipulate it:

// Add an item to the list
myPopUpbutton.addItem(withTitle: "Pop up buttons rock")

// Add an array of items to the list
myPopUpbutton.addItems(withTitles: ["Item 1", "Item 2", "Item 3"])

// Remove all items from the list
myPopUpbutton.removeAllItems()

// Get the index of the currently selected item
let selectedIndex = myPopUpbutton.indexOfSelectedItem

// Select an item at a specific index
myPopUpbutton.selectItem(at: 1)

Pretty straightforward, isn’t it? That’s the beauty of macOS controls — there are a lot of similarities between them in terms of the methods used to manipulate the controls.

Time to implement a pop up button in your app! :]

The More the Merrier — A Plural Noun

You’ll now add a pop up button to your Mad Libs application to choose between different plural nouns to populate your comical sentence.

Open Main.storyboard. Drag a label just below the Singular Noun label.

Change the alignment to Right and the title to Plural Noun:. Next, locate the Pop Up Button control and drag it onto the window, placing it to the right of the label.

The content view should look like this:

add-popup

Now you need to add an outlet to the popup button, which should be fairly familiar by now: open the Assistant editor, make sure ViewController.swift is selected, and then Ctrl-Drag the pop up button to the ViewController class to create a new outlet:

drag-popupIn the popup window, name the outlet pluralNounPopup:

popup-outlet-2

Now you just need some data to populate the control!

Open ViewController.swift and add this property inside the class implementation.

fileprivate let pluralNouns = ["tacos", "rainbows", "iPhones", "gold coins"]

Now, add the following code to the bottom of viewDidLoad():

// Setup the pop up button with plural nouns
pluralNounPopup.removeAllItems()
pluralNounPopup.addItems(withTitles: pluralNouns)
pluralNounPopup.selectItem(at: 0)

The first line removes any existing items from the pop up button. The second line adds the array of nouns to the pop up button using addItems(). Finally, it selects the first item in the list.

Build and run the application to see the result:

buildrun-popup

Once the app has launched, note that the pop up button shows the initial item, tacos, and if you click on the pop up button, you’ll see all the other items in the list.

Okay, so you now have two macOS controls that allow the user to select from lists, as well as a control that allows the user to enter a single line of text. But what if you need to type more than a few words in a text field?

Read on to learn about text views!

Text is Next – NSTextView

Text views, unlike text fields, are usually the control of choice for displaying rich text. Some implementations even allow for more advanced features such as displaying inline images.

The macOS Control responsible for this is NSTextView.

A great example of an application using all of what NSTextView has to offer is TextEdit:

textedit

NSTextView is so feature-rich that to cover everything would warrant a tutorial of its own, so here you’ll just see a few of the basic features in order to get you up and running! (Did you just breathe a sigh of relief?) :]

Here are the basic methods you’ll need to work with text views:

// Get the text from a text view
let text = myTextView.string

// Set the text of a text view
myTextView.string = "Text views rock too!"

// Set the background color of a text view
myTextView.backgroundColor = NSColor.white

// Set the text color of a text view
myTextView.textColor = NSColor.black

Relatively simple — nothing too shocking here.

NSTextView also has built-in support for NSAttributedString. If you pass an attributed string to a text view, the string will be displayed correctly using all the appropriate attributes such as font, font size, and font color.

Note: An attributed string is a special type of string where you can tag subsets of the string with different attributes – such as its font, its color, whether its bolded, and so on. To learn all about attributed strings, check out our TextKit Tutorial. It’s an iOS tutorial, but the information about NSAttributedString applies to Mac development as well.

The Phrase that Pays – Adding a Text View

Looks like you have everything you need in order to add a text view to your Mad Libs application! This text view will allow the user to enter a multi-word phrase that will be used in the final rendered Mad Lib.

Open Main.storyboard and drag a label just below the Plural Noun label (or duplicate an existing label, as mentioned earlier). Change its alignment to Right and its title to Phrase:.

Next, locate the Text View control and drag it onto the window, placing it beside the label you just created.

Your window should now look like this:

add-textview

Now, if you try to resize the view and make it taller, you’ll notice something quite particular. The text view moves along, and changes its position when you resize the window.

textview-error

That’s because by default, Xcode adds Auto resizing constraints to the text view, so that it repositions itself when its parent view is resized. Since you want the text view to stay put, you’ll need to disable some of those.

Select the Bordered Scroll View – Text View from the Document Outline and go to the Size Inspector.

In the AutoResizing section, you’ll see a rectangle which has four red lines connected to the parent view. Each one of these red connectors represents an Auto resizing constraint. You just need to click on the Right and Bottom red connectors to disable those, the solid red lines will turn to broken lines with a faded red color as shown below:

add-autores

Now, the text view stays put and aligned with the label even if you resize the window.

Next, add an NSTextView outlet to the view controller. Select the textview, open the Assistant editor and make sure ViewController.swift is selected. Ctrl-Drag from the text view to the ViewController class under the existing outlets.

Important: Text views are contained inside scroll views. It’s important you make sure you’ve actually selected the text view before creating the outlet. To do so, simply click three times on the text view or select it in the Document Outline.

textview-drag

In the popup window, make sure the type is NSTextView, and name the outlet phraseTextView.

textview-outlet2

Now, add the following code to the end of viewDidLoad():

// Setup the default text to display in the text view
phraseTextView.string = "Me coding Mac Apps!!!"

Build and run the application to see the result:

textview-result

Superb! The Mad Libs application is really starting to take shape now.

Pushing Your Buttons — NSButton

Buttons are macOS controls designed to send a message to the app whenever they’re clicked.

The control responsible for this on macOS is NSButton.

There are many different styles of buttons (you can view them in Interface Builder’s Object Library). They all work in much the same way, the only difference being their visual representation.

button-catalogYou should use the style of button that best suits your application’s design — refer to the macOS Human Interface Guidelines for advice and guidance on best design practices for your app.

Typically, when working with a button, you’ll simply need to associate an action with the button and set its title. However, there may be times when you need to disable the button, or change its appearance. The following methods allow you to perform those actions:

// disable a button
myButton.isEnabled = false

// enable a button
myButton.isEnabled = true

// getting & setting a button's title
let theTitle = myButton.title
myButton.title = theTitle

// getting & setting a button's image
let theImage = myButton.image
myButton.image = theImage

Looks fairly simple — adding a button to your app in the next section should be a breeze.

Buttoning Things Down — Adding a Button

Open Main.storyboard. Find the Push Button in the Object Library palette and drag it onto the content view. Double-click on it to change its title to Go! :

button-add

This time you don’t need to create an outlet for the button. However, you do need to create an action and associate it with the button, so that your app knows when the button has been clicked! :]

Open the Assistant Editor and Ctrl+Drag from the button to the ViewController implementation.

button-addaction

In the popup window that appears, make sure that the connection is set to Action. Name the action goButtonClicked.

button-action-2

Whenever the user clicks on the button the action method goButtonClicked() will be called. For now you’ll add some debug code, just to make sure everything’s working.

Open ViewController.swift and add the following code inside goButtonClicked():

let pastTenseVerb = pastTenseVerbTextField.stringValue
let singularNoun = singularNounCombo.stringValue
let pluralNoun = pluralNouns[pluralNounPopup.indexOfSelectedItem]
let phrase = phraseTextView.string ?? ""

let madLibSentence = "A \(singularNoun) \(pastTenseVerb) \(pluralNoun) and said, \(phrase)!"

print("\(madLibSentence)")

This code gets the strings from the text field, the combo box, the popup button and the text view and forms the Mad Lib sentence.

Note that for the text view, the string property is actually an optional, so it could be nil. To guard against that case, you’re using the nil coalescing operator ?? so if string is nil, you’ll get the empty string "" instead.

That’s all the code you need for now — build and run your app.

button-buildrun
Every time you click the button, you should see a short and silly sentence appear in Xcode’s console.

A dev ate tacos and said: Me coding Mac Apps!!!!

That’s great, but how could you make it even funnier?

How about making your computer read the sentence? Steve Jobs made the first Macintosh say hello to the world in its presentation. You can make your computer talk too… Let’s get at it!

Open ViewController.swift and add this code inside the ViewController implementation:

// 1
fileprivate enum VoiceRate: Int  {
  case slow
  case normal
  case fast

  var speed: Float {
    switch self {
    case .slow:
      return 60
    case .normal:
      return 175;
    case .fast:
      return 360;
    }
  }
}
//2
fileprivate let synth = NSSpeechSynthesizer()

First, you declare an enum to represent the voice rate. Then you create and instance of NSSpeechSynthesizer which is the class that will convert the text to speech.

Now, add this method inside the ViewController implementation:

fileprivate func readSentence(_ sentence: String, rate: VoiceRate ) {
  synth.rate = rate.speed
  synth.stopSpeaking()
  synth.startSpeaking(sentence)
}

This method starts the synth object speaking a string at the determined speed.

Time to call it! Add this code at the end of goButtonClicked() to read the Mad Libs sentence:

readSentence(madLibSentence, rate: .normal)

Build and run; click Go! and listen to your Mac saying your sentence out loud!

Where to Go From Here?

You can the download the final project containing all the source code from this tutorial up to this point.

In the second part of this tutorial, you’ll learn about more macOS controls, including sliders, date pickers, radio buttons, check boxes and image views — each of which will be added to your Mad Libs application in order to complete it.

In the meantime, if you have any questions or comments about what you’ve done so far, join in the forum discussion below!

Team

Each tutorial at www.raywenderlich.com is created by a team of dedicated developers so that it meets our high quality standards. The team members who worked on this tutorial are:

Ernesto García

Ernesto is a Mac and iOS developer from Spain. After 16+ years of experience developing Enterprise applications, now he is an indie developer who focuses on creating great mobile and desktop applications. He's the founder of CocoaWithChurros where he develops Apps for clients as well as his own. You can also find him on Twitter or Github.

Other Items of Interest

Save time.
Learn more with our video courses.

raywenderlich.com Weekly

Sign up to receive the latest tutorials from raywenderlich.com each week, and receive a free epic-length tutorial as a bonus!

Advertise with Us!

PragmaConf 2016 Come check out Alt U

Our Books

Our Team

Video Team

... 20 total!

Swift Team

... 15 total!

iOS Team

... 44 total!

Android Team

... 15 total!

macOS Team

... 11 total!

Unity Team

... 11 total!

Articles Team

... 13 total!

Resident Authors Team

... 17 total!

Podcast Team

... 3 total!

Recruitment Team

... 9 total!