Mac OS X Development Tutorial for Beginners Part 3: Your First OS X App

Sam Davies

featureImage_250

Welcome back to our 3-part Mac OS X Development tutorial for beginner series!

This introductory series about building apps on OS X has covered a lot of ground. This is what you’ve already learned:

  • Tooling: In part one you learned about the many facets of Xcode – and had a glimpse of how you could use it to start developing for OS X.
  • App Anatomy: The second part covered a lot of the theory behind how OS X app are constructed – from the data layer, through the binary assets, to designing the UI.

In this third and final part, you’re going to dive deep into the world of OS X development, by creating your first ever app!

The app you’re going to build is a magic-8 ball app, to help you make all those difficult decisions in day-to-day life. You’ll start from scratch – first creating a “Hello World!” app before moving on to creating an app to solve all your problems!

Note: This app requires OS X El Capitan and Xcode >=7.1 — make sure you upgrade before trying to follow the tutorial.

Getting Started

Open Xcode and click Create a new Xcode project to start your new app. Choose OS X \ Application \ Cocoa Application:

01_project_template

Set the product name MagicEight, the language to Swift and ensure that the Use Storyboards is checked:

02_project_options

Choose a location on disk to save your project and then click Create to open your empty project.

Build and run MagicEight to check that everything is working:

03_bar_01

Great – so the app runs, but it does absolutely nothing yet. It wouldn’t be right to start a new platform without creating “Hello World!” first…

Hello World!

The user interface for an OS X app is provided by the storyboard file, which you edit using interface builder. This allows you to design the UI in a visual manner, reducing the amount of complex code you have to write.

Open Main.storyboard by selecting it in the Project Navigator in the left-hand pane:

04_project_navigator

You’ll now see the storyboard open in the center panel:

05_storyboard

The template storyboard contains three components:

  • Menu Bar: Controls the menu that appears when the app runs.
  • Window Controller: Manages the default window that appears. Uses one or more view controllers to manage its content.
  • View Controller Responsible for a region of the window–both for display and handling user interaction.

During this introductory tutorial you’ll concentrate your efforts on the view controller.

Adding a Label

First up, you need to add a label to the view controller to display your welcome text. A label is actually a special type of NSTextField that’s designed for displaying a single line of non-editable text–perfect for “Hello World”.

To add your first label:

  1. Click the icon in the toolbar to show the utilities panel on the right-hand side.
  2. Use the icon towards the bottom of the panel to open the Object Library. This, as the name suggests, is a catalog of things you can drag onto the storyboard canvas to construct your layout.
  3. Use the search box at the bottom to search for label.
  4. You’ll see the label object highlighted in the library.

06_object_library

Drag the label from the object library onto the view controller:

07_label_vc

To change the text content of the label, select the Attributes Inspector tab of the Utilities panel, locate the Title field and enter Hello World!:

08_hello_world

You use the attributes inspector to control the appearance and behavior of the different controls that OS X offers. Find the Font entry, and click the T icon to the right to open the font panel. Change the style to Thin and the size to 40. Click Done to save the changes:

09_font

Cast your eyes back over to the view controller canvas and you’ll see something strange:

10_wrong_size

Although you’ve adjusted the text and size of the label, it has remained the same size, causing nearly all of the text to disappear. Why is this?

Basic Auto Layout

You placed the label on the view controller’s canvas, but you haven’t actually told OS X how it should position it. The view controller appears at one size in the storyboard, but once it’s running in the app, the user can change the window size–so you need to specify how the label should be positioned for any window size.

This sounds like it might be a really difficult task, but luckily Apple has your back. OS X uses a powerful layout engine called Auto Layout, in which the relationships between different components of the view are expressed as constraints. These constraints are then interpreted at runtime to calculate the size and position of each element within the view.

Note: Auto Layout is a complex topic, and this introductory tutorial won’t cover it in any great depth. If you’d like to read more on the topic then there are some excellent tutorials on the site targeted to Auto Layout on iOS—luckily the engine is almost identical on the two platforms.

Ensure that the label is selected in the view controller, and then click the Align button in the lower toolbar. Select Horizontally in Container, ensuring the value is set to 0 before clicking Add 1 Constraint to add the constraint:

11_align

This will ensure that the label will always appear in the center of the window, irrespective of its width. You’ll notice that some angry red lines have appeared in the storyboard:

12_angry_red

This is because you’ve provided a constraint that specifies the location of the label in the horizontal direction, but you’ve not provided any information about the vertical axis yet.

Once again, ensure that the label is selected in the view controller, and this time click the Pin menu on the Auto Layout toolbar at the bottom. Enter 30 in the top constraint box and ensure that the I-bar beneath it is solid red. Set the value of Update Frames to Items of New Constraints before clicking Add 1 Constraint:

13_pin

Immediately you’ll notice the view controller update—you can now see the entire label, and the angry red lines have changed to calming blue:

14_happy_storyboard

And that’s your “Hello World” app done (for now). Use the “play” button to build and run, and inspect your handiwork:

15_bar_02

Congratulations! Not very personal though is it? In the next section you’ll discover how to make the traditional greeting a little more friendly.

Handling User Input

In this section you’re going to add a text field to allow the user to enter their name so that you can welcome them personally.

Control Layout

As you did before, use the object library to locate and then drag a Text Field and a Push Button onto the view controller. Position them above the “Hello World!” label:

16_position_textfield

Remember that placing the controls on the canvas isn’t enough for OS X to understand how you want them positioned as the window changes size. You need to add some constraints to convey your wishes.

Select the text field, and then Command-Click the button to select both simultaneously. Click the Stack icon on the Auto Layout toolbar at the bottom of the storyboard:

17_stack

This has created a new stack view containing the text field and the button. A stack view automatically generates the layout constraints required to position the contained views in a line. You can use the attributes inspector to configure many common properties of the stack view.

NOTE: NSStackView has been in OS X since 10.9, but received a significant update in 10.11 (El Capitan)—in line with its introduction (UIStackView) in iOS. Stack views are similar on both platforms, so you can check out the iOS tutorial on stack views to get up to speed. Or hang tight—there’s a tutorial on NSStackView dropping in the next few weeks.

Once you’ve started stacking it’s difficult to stop. This time, you’re going to stack your newly created stack view with the “Hello World!” label—in a vertical stack view.

Use the button to the left of the lower toolbar to show the Document Outline and then locate the “Hello World” control and the existing stack view. Command-click them to select both:

18_document_outline

As you did before, use the Stack button on the bottom toolbar to create a new stack view:

19_stack

While this new stack view is selected, open the Attributes Inspector and set the Alignment to Center X, and the spacing to 20:

20_stack_config

This ensures that the label and the upper stack view are nicely centered and there’s a gap of 20 points between them.

A couple more bits of layout to complete before you can turn your attention to the task of handling user input.

The stack view handles the positioning of its content relative to each other, but it needs to be positioned within the view controller’s view. Select the outer stack view and use the Align auto layout menu to center it horizontally within its container:

21_align

And use the Pin menu to pin the stack view to the top, with a spacing of 30:

22_pin

Finally, to ensure that the text field always has the space for the user’s name, you will fix its width.

Select the text field and use the Pin menu in the bottom toolbar to specify a Width of 100. Click Add 1 Constraint to save the new constraint:

23_textfield_width

With that your layout is pretty much complete—it should look like the following:

24_layout

Now you can turn your attention back to those new controls you added.

Outlets and Actions

Select the text field and open the Attributes Inspector. In the Placeholder field type Name:

25_name

This grayed out text will instruct the user what the field is for, and disappears as soon as they start typing.

Select the button, and again open the Attributes Inspector. Set the Title to Welcome:

26_welcome

That’s the cosmetic aspect done. Time to wire these two controls into code.

OS X provides a way to interact with the storyboard UI from code using outlets and actions:

  • An outlet is a property in code that is connected to a component in the storyboard. This allows you to access the properties of controls within a storyboard from your code.
  • An action is a method on a class in code that is invoked when the user interacts with the components in the UI – e.g. by clicking on a button.

You are going to add outlets for the text field and the label, and an action that will be called when the user clicks the welcome button.

The view controller you’ve been working on already has a skeleton class associated with it in code—in ViewController.swift. This is where you’ll add the outlets and action.

Open the assistant editor using the button in the toolbar:

27_assistant_editor

This will split the screen and show a code file alongside the storyboard. It should be displaying ViewController.swift, but if it isn’t use the jump bar to select Automatic \ ViewController.swift:

28_jump_bar

Right-click-drag (or control-drag) from the text field in the storyboard over to the line above override func viewDidLoad() in ViewController.swift:

29_textfield_outlet

Ensure that Outlet is selected and call the new outlet nameTextField:

30_name_textfield

This will add the following property to ViewController and updates the storyboard to automatically connect the text field when loading the view controller:

@IBOutlet weak var nameTextField: NSTextField!

Repeat exactly the same process for the “Hello World!” label, this time specifying that the outlet should be called welcomeLabel:

31_welcome_label

Now time to turn your attention to the button. Once again Control-drag from the button in the storyboard over to the ViewController class:

32_button_action

This time, change the Connection to Action and name it handleWelcome:

33_action_settings

Click Connect to make the connection and Xcode will add the following empty method to ViewController:

@IBAction func handleWelcome(sender: AnyObject) {
}

This method will be called every time the user clicks the button.

Add the following line to the handleWelcome(_:) method body:

welcomeLabel.stringValue = "Hello \(nameTextField.stringValue)!"

This updates the stringValue property of the welcomeLabel to a welcome message constructed using the stringValue of the nameTextField. stringValue represents the value currently displayed by a text-based control—be it user-entered or defined in the storyboard.

That’s all the code you need to get your personalized version of “Hello World” going! Build and run to give it a try. Once the app has started, try entering your name in the Name box and clicking the Welcome button. You’ll see your very own version of “Hello world!”:

34_hello_sam

Pretty cool eh? Well, the fun doesn’t stop there. Next up you’re going to learn about adding images to your app, to create an amazing magic-8 ball utility!

Assets

You were promised a magic 8-ball app at the start of this tutorial, and so far you’ve seen no mention of a ball. Well, that’s all about to change.

An 8-ball is pretty distinctive, and it wouldn’t be a very exciting 8-ball app without some visualization. Download the images you’ll need to make your app look swish. You’ll find two images inside the zip file—representing the two sides of a magic 8-ball:

35_assets

Image assets are stored in an asset catalog within an OS X app. This catalog manages the different imagery and the different resolutions required for the app icons and the in-app images.

Open Assets.xcassets by selecting it in the project navigator:

36_asset_catalog

You can see that the catalog currently only contains one item – AppIcon. This is where you would put the artwork to give your app a cool icon.

You need to add the downloaded images to the asset catalog. Locate the images in finder, and drag them both into the asset catalog:

37_drag_asset_catalog

This will create two new entries in the asset catalog:

38_added_assets

Notice that there are three “cells” for the images. These cells represent the different screen scales–standard (1x), retina (2x) and retina-HD (3x). Normally you would provide assets for each of these cells, but in this simple project you will provide just one.

The image you’ve been provided is actually designed to be used at retina resolutions (2x), so drag the image from the left-hand cell to the central (2x) cell:

39_drag_retina

Repeat for both of the 8-balls assets, so that the asset catalog looks like this:

40_finished_asset_catalog

Those images are now available to use in your app—both from code and inside the storyboard.

Displaying Images

You’ve already seen how to display text, buttons and text input fields in your app, but how about images? Enter ImageView.

Open Main.storyboard and use the object library to search for image view:

41_image_view

Drag an image view onto the view controller canvas, at the bottom of the stack view. Notice how a horizontal blue line will appear denoting where in the stack view that the new image view will appear:

42_add_to_stack

Open the Attributes Inspector and set the Image property to 8ball:

43_set_8ball

This will update the canvas with the image, read from the asset catalog:

44_vc_with_image

Build and run the app to see how the image appears:

45_bar_03

Well, the image has appeared, but is clipped by the window. You can drag to resize the window in the usual way, but it would be much better if the window was correctly sized when the app starts, and then keeps a fixed size.

Window Size

The initial size of MagicEight’s window is determined by the size of the view controller in the storyboard. Select the view controller’s view in Main.storyboard and open the Size Inspector. Set the Width to 350 and the height to 480:

46_vc_size

Notice that the storyboard canvas now looks strange:

47_stange_vc

This is because the layout constraints need to be re-evaluated.

Use the Resolve Auto Layout Issues menu on the bottom auto layout menu bar and select All View in View Controller \ Update Frames:

48_fix_al

This will re-run the layout engine over the storyboard, and update the preview:

49_fixed_vc

Build and run to see how the app looks now:

50_bar_04

That looks much better. Try resizing the window—you’ll see that you can still manually drag it to sizes that don’t work for MagicEight’s layout.

You have a couple of options here—you can either update the layout so that it adapts nicely as the window changes size (e.g. to resize the image for small windows), or you can fix the window size. You’re going to take the second, easier approach.

Window Sizing

The window controller is responsible for managing the size of the window. Open Main.storyboard and select the window inside the window controller:

51_select_window

Open the Size Inspector and set the Content Size to a Width of 350 and a height of 480. Then check Minimum Content Size and Maximum Content Size ensuring that the the sizes are the same as the content size you entered:

52_content_size

Build and run MagicEight again, and attempt to resize the window. You no longer have control over the window size—it’s now fixed. Mega—just what you wanted.

You can now turn your attention back to the task in-hand—building the “magic” of the magic 8-ball. Well, nearly—there’s a bit more layout to do first.

Handling clicks

When the user clicks on the 8-ball you will switch the image to the other side and display a piece of advice. You need a new label to display this advice.

Open Main.storyboard and find the view controller scene. Use the Object Library to locate a wrapping label and drag it from the library beneath the stack view:

53_wrapping_label

You want this label to be positioned at the center of the magic-8 image, so you need to add some auto layout constraints.

Control-drag from the Multiline Label to the Image View in the Document Outline:

54_adding_constraints

Hold shift and select Center Vertically and Center Horizontally before clicking Add Constraints:

55_center_constraints

The label doesn’t automatically reposition—but you’ve handled this before. Use the Resolve Auto Layout Issues menu on the bottom auto layout toolbar to select All View in View Controller \ Update Frames:

56_fix_al

This repositions the label, and it becomes immediately obvious that you need to do some work on the appearance.

Select the multiline label, and use the Attributes Inspector to set the following:

  • Title: Piece of Advice
  • Alignment: Center
  • Text Color: Keyboard Focus Indicator
  • Font: System 20

57_label_config

Head over to the Size Inspector and set the Preferred Width to Explicit with a value of 75:

58_label_size

To get an idea of what the end product might look like, select the image view, and use the Attributes Inspector to set the Image to magic8ball:

59_change_image

Once again, click the main view and use the Resolve Auto Layout Issues\All Views in View Controller\Update Frames to update the layout:

60_magic8_layout

This is looking pretty good. You need to respond each time the user clicks on the 8-ball—time to discover gesture recognizers.

Gesture Recognizers

You were able to create an action in code that would run every time the user clicks the button. That was possible because buttons are designed to handle clicks—but the same is not true of image views.

Apple has provided a set of gesture recognizers that can be added to any view. These recognizers convert low-level mouse and trackpad input into semantic events—such as click, zoom and rotate.

You will add a click gesture recognizer to the image view, and then create a corresponding action in the view controller’s code.

In Main.storyboard, head over to the Object Library and search for click gesture. Drag the Click Gesture Recognizer out of the library and onto the image view. It will appear like this in the document outline:

61_gesture_recogniser

This gesture recognizer will be activated whenever the user clicks on the image—exactly what you want. You now need to create some new connections, and then you’ll be ready to switch over to code for the final sprint.

IB Connections

In the same way you did before, open up the assistant editor and ensure that it is showing ViewController.swift. Then create two new outlets by control-dragging from the storyboard to the code: one for the image view (call it ballImageView) and one for the multiline label (call it adviceLabel). This adds the following new outlets:

@IBOutlet weak var ballImageView: NSImageView!
@IBOutlet weak var adviceLabel: NSTextField!

You also need an action to wire up the newly-created gesture recognizer. Control-drag from the click gesture recognizer in the document outline, over to the code:

62_gesture_action

Change the Connection to Action and name it handleBallClick:

63_action_config

Click Connect and Xcode will add the following function definition to the ViewController class:

@IBAction func handleBallClick(sender: AnyObject) {
}

You’ve now finished all the work in Interface Builder, so you can switch back to the standard editor, and open ViewController.swift.

Manipulating UI from code

When the user clicks on the 8-ball you want to switch between showing some advice, or showing the “8”. This means that the handleBallClick(_:) will manipulate both the image view and the advice label.

Add the following code to handleBallClick(_:):

// 1:
if(adviceLabel.hidden) {
  // 2:
  adviceLabel.hidden = false
  ballImageView.image = NSImage(named: "magic8ball")
} else {
  // 3:
  adviceLabel.hidden = true
  ballImageView.image = NSImage(named: "8ball")
}
  1. Check whether the adviceLabel is currently visible. hidden is a boolean property on NSView (and hence NSTextField) that allows you to specify whether the view should be visible or not.
  2. If the advice label is currently hidden then show it, and change the image to the magic-side. NSImage(named:) loads the image from the asset catalog, and the image property on NSImageView specifies the image to display.
  3. Conversely, if the advice label is currently visible then hide it and switch the ball back to the “8” side.

Build and run and click the ball to see it switching between showing the “8” and the piece of advice. Pretty neat right? Notice how when you first start the app the advice is already showing? That’s not really what you want, but it’s a simple fix.

Initial Setup

When the app first starts you want to ensure that the advice label is hidden, and the 8-ball image is showing. View controllers have a perfect way of configuring this initial setup—in the form of viewDidLoad().

Once the view controller has finished loading all the view components from the storyboard, it calls viewDidLoad() to give you a chance to perform some final configuration.

In ViewController.swift, find the viewDidLoad() method and add the following body:

adviceLabel.hidden = true
ballImageView.image = NSImage(named: "8ball")

You’ll recognize this code from the click handler action—it just hides the advice label and sets the image to 8ball.

Build and run to check that you can’t see the advice from the outset.

Advice Generator

At the moment, no matter how many times you “shake” the ball, it always gives you the same advice. That’s not especially helpful. Time to add a bit of randomness.

Add the following code as a property inside ViewController—just below the class definition line:

let adviceList = [
  "Yes",
  "No",
  "Ray says 'do it!'",
  "Maybe",
  "Try again later",
  "How can I know?",
  "Totally",
  "Never",
]

This is an array of strings the make up all the different options for advice that the ball can dispense.

Head to the very bottom of the file (not within the ViewController class) and add the following extension:

extension Array {
  var randomElement: Element? {
    if count < 1 { return .None }
    let randomIndex = arc4random_uniform(UInt32(count))
    return self[Int(randomIndex)]
  }
}

This adds a new property to the standard library’s Array type that will return a random element. If the array is empty it returns nil, otherwise it generates a random index using arc4random_uniform() before returning the corresponding element.

Update the first branch (i.e. adviceLabel.hidden == true) of the if statement in handleBallClick(_:) to match the following:

if let advice = adviceList.randomElement {
  adviceLabel.stringValue = advice
  adviceLabel.hidden = false
  ballImageView.image = NSImage(named: "magic8ball")
}

This attempts to get a random piece of advice to display, and if successful updates the stringValue on adviceLabel to show it.

Build and run, and click the 8-ball a few times to start benefiting from the ball’s wisdom:

64_final_bar

Where to go from here

You can download the completed version of MagicEight here.

This Mac OS X development tutorial introductory series has given you a basic level of knowledge to get started with OS X apps–but there’s so much more to learn!

Apple has some great documentation covering all aspects of OS X development – head on over to https://developer.apple.com/library/mac/navigation/

You should also stick around on raywenderlich.com – we’ve got some awesome OS X tutorials lined up for the coming months!

If you have any comments or questions feel free to reach out on twitter, or in the comments section below!

Sam Davies

Sam is a strange mashup of developer, writer and trainer. By day you'll find him recording videos for Razeware, writing tutorials, attending conferences and generally being a good guy. By night he's likely to be out entertaining people, armed with his trombone and killer dance moves.

He'd like it very much if you were to follow him on twitter at @iwantmyrealname, seek him out as sammyd on GitHub, or check his personal site iwantmyreal.name.

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

... 19 total!

Swift Team

... 15 total!

iOS Team

... 32 total!

Android Team

... 15 total!

macOS Team

... 10 total!

Apple Game Frameworks Team

... 11 total!

Unity Team

... 11 total!

Articles Team

... 12 total!

Resident Authors Team

... 15 total!