Learn how to use common macOS UI controls like NSTextField, NSComboBox, NSButton, and more in this two-part series — updated for Xcode 11.3 and Swift 5!

Update Note: Updated for Xcode 11.3 / Swift 5 by Roberto Machorro. Previous updates by Ernesto García, 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/App, which is the template you use to create an app with a GUI on macOS. Then click Next.

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

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.

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.

Build and run.

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:

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:

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 via the Jump Bar.

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:

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

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.

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:

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.

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 :

In the popup window that appears, name the outlet singularNounCombo.

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!

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:

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:

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:

In the popup window, name the outlet pluralNounPopup:

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:

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:

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:

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.

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 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:

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.

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

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:

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.

You 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! :

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.

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

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.

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

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!