[Note: Updated for Swift 2.0/iOS9 9/1/15 SJL]

Last time we built a small application to compute the area of a pizza. Since it was missing a model, we are going to make an improved version of the application and add a model class, plus make a few UI changes. Since there are so many changes, we’ll start from the beginning. If you did not read the last post in the series, you will be fine though you might want to catch up on the concepts discussed earlier here. I’ll assume you have at least Xcode 7, and have some clue how to set up a story board and view controller.
Set Up the Storyboard
In Xcode, Create a new single-view Swift project. Call it PizzaDemo2. Go into the storyboard. On the bottom center of the storyboard, you will find the class sizes button labeled w:Any h:Any. Click the button and change the class size to Compact Width Any Height:
To the storyboard add a label, two buttons, and a segmented control. Make one of the buttons with a red background and white lettering, make the title of the button read Clear. Set the second button to a white foreground lettering and a blue background, but don’t set a title yet. Make the Segmented control four segments with Cheese, Sausage, Pepperoni,and Veggie. Your layout should look something like this
I did not use constraints here, but if you want to you certainly can.
Set Up the View Controller
Open the assistant editor, and control drag the controls to make the following IBOutlets
and IBActions
. note in the comments which one is the red and which one is the blue button. Remember from last time to physically change from an outlet to an action for the buttons and the segmented controls. Interface builder picks an outlet by default.
@IBOutlet var resultsDisplayLabel : UILabel! @IBAction func pizzaType(sender : UISegmentedControl) { } @IBAction func sizeButton(sender : UIButton) { //blue button } @IBAction func clearDisplayButton(sender : UIButton) { //red button }
Finish Setting up the View
In the last post in this series, we used a slider to specify pizza size. We will use preset buttons this time. We are going to use our blue sizeButton
to specify the size in its label. Go back into interface builder and click once on the blue button. Copy the button, then paste it 6 times. Change the titles and arrange the buttons to look like this:
In case you have never done this before, this is a way to have multiple buttons use the same IBAction
. The properties can be different for the buttons, in our case the titles, but they react exactly the same to being pressed. Our model will take the title string and convert it into a pizza size.
Make the Basic Model and Properties
Between the import
and the class ViewController:
code, make a little space and add the following:
class Pizza { let pi = 3.1415926 let maxPizza = 24.0 var pizzaDiameter = 0.0 var pizzaType = "Cheese" }
With that small amount of code, we created a class with two properties and two constants. That’s it. Swift does require initialized values, thus we have to specify an initialization value. Implicit typing figures out what type to use by our initialized values. When we declare a variable in a class in Swift, it becomes a property of that class. Similarly declaring a constant becomes a constant of the class.
Add a Method..or is it a Function?
Adding methods is also easy. We did it last time in the view controller. A function within a class becomes a method of that class.
A Computational Method
Add the following under var pizzaType = "Cheese"
func pizzaArea() -> Double{ return radius * radius * pi }
We have not had a case yet where we return a value until now. The pizzaArea()
method returns a double. In Objective-C, and many C syntax languages we have the return value first, something like -(Double)pizzaArea{}
In Swift, the return value is on the end with an operator ->
to specify the type of the return value. if there is no return value, it is the equivalent of (void)
in C-syntax languages. In this case we return the area.
We are getting a syntax error now since radius is not defined. We’ll come back to radius shortly and show one of the really cool features of Swift.
Swift’s Switch Switch
Swift made a few changes to the switch
control Add this method under pizzaArea():
func diameterFromString(aString:String) -> Double { switch aString { case "Personal": return 8.0 case "10\"": return 10.0 case "12\"": return 12.0 case "16\"","15\"": return 16.0 case "18\"": return 18.0 case "24\"": return 24.0 default: return 0.0 } }
Switch in Swift does not use breaks. We can also list several cases for each case, so a 15″ and a 16″ pizza returns 16. The Swift switch
does need all cases be covered, so the default:
case is mandatory to catch everything not stipulated above the default. In our example, this will send 0.0 when we press the None button since it is not a specified size.
This method also has a parameter. We specify the variable name and then the type, separated by a colon for parameters.
Create Computed Properties
We we still need the radius. We could make a method to do this, but there is another way. Add the following code between the pizzaArea()
and the var pizzaType="Cheese"
declaration.
var radius : Double { //computed property get{ //must define a getter return pizzaDiameter/2.0 } set(newRadius){ //optionally define a setter pizzaDiameter = newRadius * 2.0 } } var area : Double { get{ return pizzaArea() } }
Line 1 and line 10 declares a computed property, a property based on the values of other properties. Computed properties must declare their type, and must include a getter. Within the block after the declaration, we declare a getter named get
which returns a value computed by the already declared property pizzaDiameter
. Optionally you can include a setter for the property, as we did in line 5 for the radius. In our second example, we made a second computed property with only a getter for the area, which uses a method in our class.
Use the Model in the Controller
We can now use our model in our code. Before we do let’s write a handler for the clear button. Change clearDisplayButton
to this:
@IBAction func clearDisplayButton(sender : UIButton) { resultsDisplayLabel.text = clearString }
For our initial setup change viewDidLoad
to this:
override func viewDidLoad() { super.viewDidLoad() resultsDisplayLabel.text = clearString view.backgroundColor = UIColor(red:0.99,green:0.9,blue:0.9,alpha:1.0) }
Just under the view controller’s class declaration add the following:
let pizza = Pizza() let clearString = "I Like Pizza!"
Line 2 is a simple string constant declaration used for clearing the label. Line 1 is all we need to instantiate a pizza object: declare the object as a constant and give a class for the object. Even though pizza
is a constant, its properties are not constants. This works, and keeps better memory allocation than using var
. Now add a display method for the label:
func displayPizza(){ let displayString = String(format:"%6.1f inch %@ Pizza",pizza.pizzaDiameter, pizza.pizzaType) resultsDisplayLabel.text = displayString }
In line 2, we use dot notation to use the properties of the pizza
instance. We do the same for methods as well. Add the following code for the size button:
@IBAction func sizeButton(sender : UIButton) { pizza.pizzaDiameter = pizza.diameterFromString(sender.titleLabel!.text!) displayPizza() }
The size button reads the title of the button called sender
, and assigns the correct size for a pizza to pizza
. Line 2 calls in pizza
the method diameterfromString()
through dot notation.
Now add the handler for selecting a pizzaType:
@IBAction func pizzaType(sender : UISegmentedControl) { let index = sender.selectedSegmentIndex pizza.pizzaType = sender.titleForSegmentAtIndex(index)! displayPizza() }
Line 2 gets the index of the segment selected. Line 3 get a string with the type of pizza from the segement’s label. You’ll notice the !
after the function here and in line 2 of the sizeButton
code. This is a forced unwrap operator. For this lesson, just put them in – I’ll explain them in the next lesson
We have gotten everything into place, and can now build and run.
We didn’t display anything for the area like we did in the first computer. Next time we will add some more functionality by using some collection types to our pizza computer to sell pizza by the square inch so we can calculate quickly how much to sell a pizza for.
The Whole Code
I should have made this two files: one for the model and one for the controller. However, since Swift lets me put them in one file, I did that to make copying and pasting a bit easier.
// // ViewController.swift // pizzaDemo version 2 // adds a model class to demonstrate class // // Created by Steven Lipton on 6/8/14. // Revised by Steven Lipton on 9/1/15 for Swift 2.0 (Beta 4 tested) // Copyright (c) 2014 Steven Lipton. All rights reserved. // // import UIKit /* -------- Our model for MVC keeps data and calculations about pizzas note: for ease in copying I left this in one file you can make a separate file and use import instead. ------------*/ class Pizza { let pi = 3.1415926 let maxPizza = 24.0 var pizzaDiameter = 0.0 var pizzaType = "Cheese" var radius : Double { //computed property get{ //must define a getter return pizzaDiameter/2.0 } set(newRadius){ //optionally define a setter pizzaDiameter = newRadius * 2.0 } } var area : Double { get{ return pizzaArea() } } func pizzaArea() -> Double{ return radius * radius * pi } func diameterFromString(aString:String) -> Double { switch aString { case "Personal": return 8.0 case "10\"": return 10.0 case "12\"": return 12.0 case "16\"","15\"": return 16.0 case "18\"": return 18.0 case "24\"": return 24.0 default: return 0.0 } } } /*---------- The View Controller -----------------*/ class ViewController: UIViewController { let pizza = Pizza() let clearString = "I Like Pizza!" @IBOutlet var resultsDisplayLabel : UILabel! func displayPizza(){ let displayString = String(format:"%6.1f inch %@ Pizza",pizza.pizzaDiameter, pizza.pizzaType) resultsDisplayLabel.text = displayString } @IBAction func pizzaType(sender : UISegmentedControl) { let index = sender.selectedSegmentIndex pizza.pizzaType = sender.titleForSegmentAtIndex(index)! displayPizza() } @IBAction func sizeButton(sender : UIButton) { pizza.pizzaDiameter = pizza.diameterFromString(sender.titleLabel!.text!) displayPizza() } @IBAction func clearDisplayButton(sender : UIButton) { resultsDisplayLabel.text = clearString } override func viewDidLoad() { super.viewDidLoad() resultsDisplayLabel.text = clearString view.backgroundColor = UIColor(red:0.99,green:0.9,blue:0.9,alpha:1.0) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } }
Leave a Reply