March 31st, 2017
Filed under: Cocoa, Mac Development | 3 comments
I’ve noticed there aren’t many articles or tutorials online about writing Mac apps in Swift. To help fill the void I’m writing this tutorial that guides you through the creation of a simple Cocoa app in Swift.
The app converts temperatures from Celsius to Fahrenheit. Enter a temperature in Celsius, click a Convert button, and the app shows the temperature in Fahrenheit. I can’t think of a simpler app to introduce Cocoa programming.
The screenshots in this article are from Xcode 8.3. If you are using a different version of Xcode, some screens may look different.
Open Xcode and choose File > New > Project. The New Project Assistant opens. Select Cocoa Application, which is in the macOS section.
Click the Next button to move to the next step.
Enter a name for the project in the Product Name text field. I chose the name TemperatureConverter
.
Select None from the Team menu. Teams are used to submit apps to the App Store. This project isn’t going on the App Store.
The organization name appears in the copyright notice of new source code files Xcode creates. If you don’t have an organization name, enter your name in the Organization Name text field.
The organization identifier is a way to uniquely identify yourself and the app you’re creating for things like preference files. There should be no spaces in the organization identifier. Something like com.YourOrganizationName
should work fine for this project.
Choose Swift from the Language menu.
Starting with Xcode 8.3 Cocoa application projects use storyboards by default. If you’re using an earlier version of Xcode, you should see a Use Storyboards checkbox. Select the Use Storyboards checkbox.
Deselect the Create Document-Based Application and Use Core Data checkboxes. You can also deselect the Include Unit Tests and Include UI Tests checkboxes if you want.
Click the Next button to move to the last step of the project creation process. Choose a location to save your project. If you want to put your project under version control, select the Create Git repository checkbox. Click the Create button.
When you create the project, the left side of the project window shows all the files in the project. The two files you will be working with in this tutorial are ViewController.swift
and Main.storyboard
. ViewController.swift
contains the source code. Main.storyboard
contains the user interface.
To create the user interface for this project, you must open Main.storyboard
. Select Main.storyboard
from the left side of the project window to open the storyboard. The initial storyboard Apple provides for a Cocoa application looks similar to the following screenshot:
Xcode provides a menu bar, a window controller for an empty window, and a view controller for the window’s content view. To build the user interface for this project, you’re going to add the following items to the view controller:
The user interface elements are in Xcode’s object library. Choose View > Utilities > Show Object Library to open the object library, which is in the lower right corner of the project window.
There is a search field at the bottom of the object library you can use to filter user interface elements. Type Label
to find the label. Type Text Field
to find the text field. Type Button
to find a button.
Drag a user interface element from the object library to the view controller. Double-click on a label or button to change its text.
When you are finished the view controller should look similar to the following:
I used a push button for the Convert button.
Select the file ViewController.swift
from the left side of the project window. What you need to do is add outlets for the Celsius text field and the Fahrenheit label so you can access them in your code.
@IBOutlet weak var celsiusTextField: NSTextField!
@IBOutlet weak var fahrenheitLabel: NSTextField!
Let’s go through the outlet declarations piece by piece.
@IBOutlet
tells the compiler the variable is an outlet so you can make a connection to it in Interface Builder, which is the part of Xcode you use to design user interfaces.weak
says the outlet is a weak reference. If you remove the word weak
the outlet becomes a strong reference. Weak and strong references deal with Cocoa’s memory management. A deeper explanation is beyond the scope of this tutorial.var
says the outlet is a variable and not a constant. Outlets must be variables.var
is the name of the variable.NSTextField
tells the compiler the type of the outlet. The outlets in this tutorial are text fields. Labels are text fields whose values can’t be edited.The exclamation point after NSTextField
requires more explanation. The exclamation point tells the compiler the outlet is an implicitly unwrapped optional. An optional value may or may not exist. Declaring the two outlets doesn’t mean the text field and label exist in the storyboard. The app won’t know until it launches the storyboard and loads the window and its contents.
An implicitly unwrapped optional states the variable is guaranteed to exist. If an implicitly unwrapped optional does not exist and your app accesses it, the app crashes. In your Swift code you should avoid using implicitly unwrapped optionals because they can cause your app to crash. Implicitly unwrapped optionals are OK to use for outlets because the storyboard is going to load. If the text field and label don’t exist, the app isn’t going to work so you might as well crash.
Now you need to connect the text field and label in the storyboard to the outlets you created. If you don’t make these connections, your app will crash when it runs.
Open Xcode’s assistant editor so you can have the files ViewController.swift
and Main.storyboard
open at the same time. Choose View > Assistant Editor > Show Assistant Editor to open the assistant editor. Open ViewController.swift
in one editor and Main.storyboard
in the other editor.
Select the Celsius text field in the storyboard. Hold down the Control key and drag it to the celsiusTextField
variable in the source code file. When you reach the variable, it should highlight and there should be an option to connect the outlet. Release the mouse button when it says Connect Outlet.
Making connections in Xcode can be frustrating. Sometimes the Connect Outlet option does not appear. Keep trying and eventually you will be able to make the connection.
After connecting the Celsius text field, connect the label. Select the label. It should be the one with the value 0, not the one that says Fahrenheit Temperature. Control-drag the label to the fahrenheitLabel
variable. Choose Connect Outlet. When you connect the outlets, the left side of the editor has a connection symbol for the outlets, as you can see in lines 13 and 14.
Now it’s time to start writing code. Open the file ViewController.swift
and add the following two functions:
@IBAction func convertToFahrenheit(_ sender: AnyObject) {
if let celsiusTemperature = Float(celsiusTextField.stringValue) {
let fahrenheitTemperature = convert(celsius: celsiusTemperature)
fahrenheitLabel.stringValue = fahrenheitTemperature.description
}
}
func convert(celsius: Float) -> Float {
return ((celsius * 1.8) + 32.0)
}
Let’s look at the signature of the convertToFahrenheit
function.
@IBAction
tells the compiler the function is an Interface Builder action so you can connect the Convert button to it.func
is the keyword to declare a Swift function.sender
, which has type AnyObject
. All Interface Builder actions take a sender as an argument. The _ character before sender
means you don’t have to type sender:
when calling convertToFahrenheit
the way I typed celsius:
when calling the convert
function.What complicates the convertToFahrenheit
function is the fact that text fields and labels store strings. You cannot do calculations with strings because strings might not have numeric values. To convert the temperature to Fahrenheit, you need to convert the value of the Celsius text field to a floating-point number. That’s what the first line of code does. The if let
statement allows you to safely handle the situation where there’s no number in the text field. If someone enters XYZ
in the Celsius text field, the function returns without doing anything.
The second line calls the function to convert the Celsius temperature to Fahrenheit. The third line sets the Fahrenheit label’s text to the Fahrenheit temperature.
The convert
function takes the Celsius temperature and returns the Fahrenheit temperature using the following formula:
F = (1.8 * C) + 32
Now the last step is to connect the Convert button so that the conversion occurs when you click the button. Open Main.storyboard
. You should see the object list on the left side of the editor.
Select the Convert button. Control-drag to the First Responder object in the view controller scene. You won’t be able to connect to the First Responder object in the application scene. When you make the connection, a HUD opens with a long list of actions to choose from. Select convertToFahrenheit
. Now when someone clicks the Convert button, it calls the convertToFahrenheit
function.
Xcode projects are initially set to use code signing so you can submit your apps to the App Store. Code signing requires you to be a member of Apple’s paid developer program. I can’t assume everyone reading this article is a member of Apple’s paid developer program. That’s why I had you choose None from the Team menu when you created the project. Because there is no team you have to turn off code signing for the project to get the project to build.
To turn off code signing, perform the following steps:
In the upper left corner of the project window is the Run button, which looks like the Play button on a DVD player. Click the Run button to build your project and run it.
If you run into problems building the project, make sure there are no typing mistakes in your code. Making a tiny mistake typing the name of a variable or function is enough to prevent the compiler from building your project.
If the app crashes when you run it, make sure you connected the outlets. My Finding Where Your App Crashes in Xcode article can help you locate the cause of the crash.
If clicking the Convert button does nothing, make sure you connected the button to the IBAction and make sure you entered a numeric value in the Celsius text field.
If all else fails, I have the project on GitHub for you to download.
You could build upon this project by making the conversion from Fahrenheit to Celsius.
To learn more about Cocoa programming, you best source is Apple’s documentation, which you can access in Xcode by choosing Help > Documentation and API Reference. I wish I could recommend a book on Mac development, but when I searched Amazon for Cocoa programming books, the last book was published in April 2015 and used Swift 1.
Tags: storyboard, swift
Thank you for this helpful tutorial. I wasn’t sure what to do after the Use Storyboards checkbox (which I always deselected) disappeared in Xcode 8.3!
Ken,
Xcode 9 brings back the Use Storyboards checkbox. A lot of people must have complained about the checkbox being removed in Xcode 8.3.
Mark, Thanks for the info. That’s good news!