Category Archives: Tutorial

Custom Table View Cells in Swift 3

2016-10-14_06-53-47In iOS you are limited to two labels and an image for one of the standard table view cell styles. You might want more custom cells than this. You are not alone with  other developers including, Instagram, Twitter, Feedly and even Apple often using more than the basic table view cell. You can customize table view cells and populate them with any number of views in any size. In this lesson, I’ll show you how to make a custom table view cell to display four labels. We’ll add some logic to the custom view to conditionally show two labels for specials and give a 10% discount.

I’ll modify the app I created in the Table Views in Subviews Lesson. You can go to that lesson to learn more or download the starter file pizzatable_customcell_start.zip.

Creating a Custom Cell

Go to the storyboard. In the document outline, select the cell

2016-10-14_07-13-44

In the attributes inspector, Change the style to Custom.

2016-10-14_07-16-24

The  height of the custom cell will be bigger than the standard 44 point height. Click the ruler to change from the attributes inspector to the size inspector.  You’ll find the row height at the top of the inspector. Click on Custom and change from the default 44 points to 75 points.

2016-10-14_07-20-29

Click back to the attributes inspector. Drag four labels into the table view cell. Change the labels to Menu Item DescRegular Price $99.99, Special, and $99.99

 2016-10-14_07-24-48

Drag the labels to the four corners of the cell. Use the blue guides to align them to the corners.

2016-10-14_07-28-28

Select the Menu Item Desc Label. In the attributes inspector, change the font to a custom font of Georgia 24 point. Set AutoShrink to Minimum Font Scale of 0.5. In case the description is too long, this will shrink the font to fit.

2016-10-14_07-30-46

Select Special. Change the font color to Red(#ff0000) and the Font to System Heavy 17.0. Right align the label. Select the $99.99   label. right align the label and set the font to Gerogia 22 point.

2016-10-14_07-37-36

I’ll use  auto layout to lay things out cleanly.  Select Menu Item Desc. Control-drag up and to the left until the content view highlights.

2016-10-14_07-38-58

Release the mouse button. A menu appears.  Shift select Leading Space to Container Margin, Top Space to Container Margin and Equal Widths.

2016-10-14_07-40-55

This pins the label to the upper right side, and sets the width of the label to the width of the cell. I want 70% of the cell to be the label. With the label selected, Click on the width constraint, which should have some number like -198 in it

2016-10-14_07-45-31

In the attributes inspector, change the multiplier to 0.7

2016-10-14_07-48-18

Select the Regular Price $99.99 label. Control-drag from this label down and to the left until the content view highlights. Release the mouse button.  Shift select Leading Space to Container Margin, Bottom Space to Container Margin, and Equal Widths.

2016-10-14_07-50-38

Click Add constraints.  Select the width constraint

2016-10-14_07-52-19

Change the width of this label to 60% of the cell. In the attributes inspector, change the Multiplier to 0.6.

2016-10-14_07-56-51

Select Special, then Control-drag Up and to the right. Shift-Select Trailing Space to Container margin and Top Space to Container margin. Click Add Constraints

2016-10-14_07-58-10

Select Special, then Control-drag up and to the right. When you release the mouse button, select Trailing Space to Container margin and Bottom Space to Container Margin.  Click Add Constraints.

2016-10-14_07-58-46

Click the resolverresolver button. In All views in Table View Cell, select Update Frames.

2016-10-14_08-00-13

The cell’s format looks like this, with each label constrained to the corner.

2016-10-14_08-01-04

Connecting Up the Cell

Table view cells need their own class for outlets and actions.  Press Command-N to create a new Cocoa Touch Class Named CustomTableViewCell, subclassing UITableViewCell. Create the file. Once created, return to the storyboard. Select the cell in the document outline.  In the Identity inspector, change the class of the cell to CustomTableViewCell.

2016-10-14_09-33-57

Hide the right ad left inspector panes to give ourself some room for the assistant editor.  Click the assistant editor. You see code for the table view controller. To get to the cell’s controller class is slightly tricky. Xcode does not yet know it is there. You have to manually select it.  In the Assistant editor,  click where it says Automatic. In the menu tree that appears select Manual>PizzaTable>PizzaTable>CustomTableViewCell.swift

2016-10-14_09-39-05

 Make  four outlets for the labels. Control drag from the Menu Item Desc to the code to make an outlet menuItemDescLabel. Control-drag from the Special label to make an outlet specialLabel. Control Drag from Regular price $99.99 to make an outlet regPriceLabel. Control drag the $99.99 label to make the outlet priceLabel. Close the assistant editor.

Functions For the Cell

Open the left inspector and in the navigator go to the CustomTableViewCell.swift file. In the class just under the outlets,  add two constants for color and a discount amount for specials.

let lightGreen = UIColor(red: 0.5, green: 1.0, blue: 0.5, alpha: 1.0)
let lightRed = UIColor(red: 1.0, green: 0.9, blue: 0.9, alpha: 1.0)
let discount = 0.1

The cell can do much of its own setup and formatting, leaving the table view controller a lot cleaner and free of code. Add a function to convert the price to a string in the cell, which also concatenates a string in front of the price.

func string(_ prefix:String, for price:Double) -> String{
    let priceString = String(format: "%2.2f", price)
    return prefix + priceString
}

When an item is on special, it has a 10% discount. I’ll show the discounted price, the regular price and print the word Special on the cell if it is a special. To attract even more attention, I’ll make the background light green.  If not a special, I’ll make the background light red, and show just the price.  Add all that as a function.

func show(isSpecial:Bool,for price:Double){
    if !isSpecial{ //normal
        regPriceLabel.text = ""
        specialLabel.text = ""
        priceLabel.text = string("$", for: price)
        contentView.backgroundColor = lightRed    
    } else { //special discount
        regPriceLabel.text = string("Regular price $", for: price)
        specialLabel.text = "Special"
        priceLabel.text = string("$", for: price * (1.0 - discount))
        contentView.backgroundColor = lightGreen
    }
}

Using the Cell

You’ve set up the custom cell and added a controller to it. Change the Table view controller to use the cell.  Go over the TableViewController.Swift file. Find the tableView(tableview:CellForRowAt index path) method. Comment it out or delete it. I’ll start this from scratch. Add the method in again

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
       
}

For  the first line create a cell by dequeuing a reusable cell as you have for any other table view. However, downcast the cell to CustomTableViewCell. Add the code to return the cell

let cell = tableView.dequeueReusableCell(
     withIdentifier: "cell",
     for: indexPath) as! CustomTableViewCell
        
return cell

the rest of the code goes above the return. Add a constant for the row from the index path.

let row = indexPath.row

The model has three arrays for price of a menu item, names of menu items and a bool for specials.  To add the menu item name, just assign it to the outlet menuItemDescLabel's text property.

cell.menuItemDescLabel.text = menuItems.names[row]

That’s all you need for many controls: just passing values to its outlets. You  can use a function from the cell controller.  For the price,  there is the function show(isSpecial:,for price:) in the cell. I call that and it decides how to display the other three labels.

cell.show(
    isSpecial: menuItems.specials[row],
    for: menuItems.prices[row]
)

The final method is this:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
   let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomTableViewCell
   let row = indexPath.row
   cell.menuItemDescLabel.text = menuItems.names[row]
   cell.show(isSpecial: menuItems.specials[row], for: menuItems.prices[row])
   return cell
}

Configuring the Cell Height

Once you change the cell height, you must tell the table view the row height using the rowHeight property.  In viewDidLoad add the following.

 tableView.rowHeight = 75

This is the same number from the storyboard. I went simple here and just took the 75 points from the storyboard. There are more sophisticated ways to find the height, but I often go this simple route.

Running the Application

Build and run,

2016-10-14_11-53-43

Usually you’ll see two labels with the description and price in each cell. For a special, the cell changes to include the extra two labels, with the discount reflected. If you select an item, the functionality almost works. For a regular item the numbers are correct.

2016-10-14_11-55-37

However a special gives the regular, not the discounted price.

2016-10-14_11-55-57

Stop the simulator.  Change the tableview(tableview:didSelectRowAtIndexPath:) method to this:

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let discount = 0.1
    let row = indexPath.row
    let name = menuItems.names[row]
    var price = menuItems.prices[row]
    if menuItems.specials[row]{price *= (1.0 - discount)} //adjust for discount
    delegate.didSelectItem(name: name , price: price)
}

This changes the price if the item is on special. Usually the price is the one given, if not, multiply off the discount. Try running again and the special discounts work.

2016-10-14_12-02-16

I kept the example to a few labels. What you can do in a table view cell is almost everything you can do in a view. You could add more advanced views, animations,  media players, and more as outlets. You can add buttons and switches to the cell, and set actions in CustomTableViewCell to change the cell or the app.

The Whole Code

You can download the completed project here: pizzatable_customcel.zip Below you will find a complete listing of the code.

CustomTableViewCell.swift

//
//  CustomTableViewCell.swift
//  PizzaTable
//
//  Created by Steven Lipton on 10/14/16.
//  Copyright © 2016 Steven Lipton. All rights reserved.
//

import UIKit

class CustomTableViewCell: UITableViewCell {

    @IBOutlet weak var menuItemDescLabel: UILabel!
    @IBOutlet weak var specialLabel: UILabel!
    @IBOutlet weak var regPriceLabel: UILabel!
    @IBOutlet weak var priceLabel: UILabel!
    
    let lightGreen = UIColor(red: 0.5, green: 1.0, blue: 0.5, alpha: 1.0)
    let lightRed = UIColor(red: 1.0, green: 0.9, blue: 0.9, alpha: 1.0)
    let discount = 0.1
    
    func string(_ prefix:String, for price:Double) -> String{
        let priceString = String(format: "%2.2f", price)
        return prefix + priceString
    }
    
    func show(isSpecial:Bool,for price:Double){
        if !isSpecial{
            regPriceLabel.text = ""
            specialLabel.text = ""
            priceLabel.text = string("$", for: price)
            contentView.backgroundColor = lightRed
            
        } else {
            regPriceLabel.text = string("Regular price $", for: price)
            specialLabel.text = "Special"
            priceLabel.text = string("$", for: price * (1.0 - discount))
            contentView.backgroundColor = lightGreen
        }
    }
    
    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override func setSelected(_ selected: Bool, animated: Bool) {
        super.setSelected(selected, animated: animated)

        // Configure the view for the selected state
    }

}

TableViewController.swift

//
//  TableViewController.swift
//  PizzaTable
//
//  Created by Steven Lipton on 10/2/16.
//  Copyright © 2016 Steven Lipton. All rights reserved.
//

import UIKit

protocol TableViewControllerDelegate{
    func didSelectItem(name:String,price:Double)
}

class TableViewController: UITableViewController {
    var menuItems = MenuItems()
    var delegate:TableViewControllerDelegate! = nil
    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return menuItems.names.count
    }
    
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! CustomTableViewCell
        let row = indexPath.row
        cell.menuItemDescLabel.text = menuItems.names[row]
        cell.show(isSpecial: menuItems.specials[row], for: menuItems.prices[row])
        return cell
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let discount = 0.1
        let row = indexPath.row
        let name = menuItems.names[row]
        var price = menuItems.prices[row]
        if menuItems.specials[row]{price *= (1.0 - discount)} //adjust for discount
        delegate.didSelectItem(name: name , price: price)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.rowHeight = 75

      }
}

ViewController.swift

//
//  ViewController.swift
//  PizzaTable
//
//  Created by Steven Lipton on 10/6/16.
//  Copyright © 2016 Steven Lipton. All rights reserved.
//

import UIKit



class ViewController: UIViewController,TableViewControllerDelegate {

    @IBOutlet weak var pizzaOrderedLabel: UILabel!
    @IBOutlet weak var priceLabel: UILabel!
    
    func didSelectItem(name: String, price: Double) {
        pizzaOrderedLabel.text = name
        let priceText = String(format:"Price: %02.2f", price)
        priceLabel.text = priceText
    }
    

    // MARK: - Navigation
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "table"{
            let vc = segue.destination as! TableViewController
            vc.delegate = self
        }
    }


}

MenuItems.swift

//
//  MenuItems.swift
//  SwiftTableViewDemo
//
//  Created by Steven Lipton on 10/1/16.
//  Copyright © 2016 Steven Lipton. All rights reserved.
//

import UIKit

class MenuItems:NSObject{
    let names:[String] = [
        "Margherita Pizza","BBQ Chicken Pizza",
        "Pepperoni Pizza","Sausage Pizza",
        "Seafood Pizza","Sausage Deep Dish",
        "Meat Lover's Deep Dish","Veggie Lover's Deep Dish",
        "BBQ Chicken Deep Dish","Mushroom Deep Dish",
        "Tiramisu","Vanilla Ice Cream",
        "Apple Crostata","Hot Fudge Pizza",
        "Soft Drink","Coffee",
        "Espresso","Mineral Water"]
    let prices:[Double] = [
        7.95,11.49,
        8.45,8.45,
        12.75,10.65,
        12.35,10.00,
        16.60,11.25,
        6.50,2.25,6.50,
        9.75,1.25,
        1.25,3.50,3.75
    ]
    let specials:[Bool] = [
        false,true,
        false,false,
        false,false,
        true,false,
        false,true,
        false,false,
        false,true,
        false,false,
        true,false]
}

Introducing Table Views in Swift 3

2016-10-02_13-55-11Table views on any mobile platform are the workhorse of any application. To be a good developer you need  to make table views easily. Tables in iOS  use the UITableView class to do so. This is a very powerful class with many features to make the tables you see in applications like Facebook, Instagram and Apple Music.

Because of the power and flexibility you have available to build tables, they are not as easy to create as a UIButton or UILabel. In this lesson I’ll introduce you to dynamic tables, and show you how to display a dynamic table. We’ll put together a menu of pizzas displaying the name of the pizza and the price.

Setting Up the Application

We’ll need to set up an application. This requires pretty robust model full of data. to save you the trouble of typing all that in, you can download this starter file: pizzatable_start.zip  You can jump down to the Set up the Storyboard section, if you use the starter file. If you want to know what I did, or type it all in your self, I’ll very briefly tell you what’s in those files.

Create a new Single View project named PizzaTable. Use Swift as the language and Universal as the device. Once loaded, Press Command-N and make a new iOS cocoa touch class named MenuItems, subclassing NSObject. Create the class like this:

class MenuItems:NSObject{
let names:[String] = [
    "Margherita Pizza","BBQ Chicken Pizza",
    "Pepperoni Pizza","Sausage Pizza",
    "Seafood Pizza","Sausage Deep Dish",
    "Meat Lover's Deep Dish","Veggie Lover's Deep Dish",
    "BBQ Chicken Deep Dish","Mushroom Deep Dish",
     "Tiramisu","Vanilla Ice Cream",
     "Apple Crostata","Hot Fudge Pizza",
     "Soft Drink","Coffee",
     "Espresso","Mineral Water"]
let prices:[Double] = [
    7.95,11.49,
    8.45,8.45,
    12.75,10.65,
    12.35,10.00,
    16.60,11.25,
    6.50,2.25,
    6.50,9.75,
    1.25,1.25,
    3.50,3.75
]
let specials:[Bool] = [
        false,true,
        false,false,
        false,false,
        true,false,
        false,true,
        false,false,
        false,true,
        false,false,
        true,false
]
}

The class has three properties as arrays, the name of the menu Item, the price, and if it is a special or featured item.

We will not be using the ViewController.swift file. Select it, delete it and move it to the trash.

Set Up the Storyboard

In the storyboard,select the view controller scene and delete it. Find the Table View Controller in the object Library.

2016-10-02_12-29-17
Drag a table view controller on the story board. In the Attribute Inspector, click on Is Initial View Controller.
2016-10-02_12-30-49

In the document outline, select Table View Cell.
2016-10-02_12-32-48

Select the menu in the attributes inspector for Style.You have several styles of menu.

2016-10-02_12-35-00
We’ll place the pizza name on the left and the price in a smaller font on the right. Select Right Detail which has this style.

Under the style, you’ll find the identifier. Your code will use this identifier to find the cell. Name it cell
2016-10-02_12-38-36

Press Command-N. Make a new iOS Cocoa Touch Class named TableViewController. There is a UITableViewClass, but it is easier to not use it. The template has so many methods, it’s confusing. Instead, subclass UIViewController, and save the file. When the code appears, change the The UIViewController subclass to UITableViewController.

class TableViewController: UITableViewController {

Delete everything else but viewDidLoad. The class should look like this:

class TableViewController: UITableViewController {

override func viewDidLoad() {
super.viewDidLoad()

}
}

Go to the storyboard. In the document outline, select the Table View Controller Scene. Select the identity inspector and set the class to TableViewController.
2016-10-02_13-00-33

Table View controllers don’t use outlets or actions if you set them up this way. Everything else is code.

Coding a Table View Controller

Coding a table view controller requires you to do three things: declare how many sections you have in your table, declare how many rows you have in each section, and populate each cell with data.

Before you do any of that, add the model. Go to the TableViewController.swift file. In the class add the following declaration:

var menuItems = MenuItems()

In many tables, there’s only one section. Our menu only has one section. For more on multiple sections, see my longer article Create Dynamic and Static Table View in Swift 3. We set the sections by overriding the numberOfsections(in tableView:) method. All we do in the code is return 1. Add this to the code:

override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

To declare the number of rows for the sections, we override the tableView(_ tableView: NumberOfRowsInSection section:) method. The number of rows are equal to the number of menu items. Add this:

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return menuItems.names.count
    }

The last required method populates the cell. This one is a bit more involved. Add the override to the class:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
    }

 

This method returns a cell with the proper data. The parameters are the table view and the location in the table, know as the indexPath. Type IndexPath has two important components: the section and the row in that section. We’ll  make a cell corresponding to the location indexPath in the table. Add this to the cellForRowAtIndexPath method:

let cell = tableView.dequeueReusableCell(
    withIdentifier: "cell",
    for: indexPath)

cell is of type UITableViewCell, which has several properties you can use. The two most important are the UILabels textLabel and detailTextLabel. They are labels which can get arranged differently depending on the style we use. You’ll take a value from the arrays in menuItem, and display it on these labels.
You’ll need an index for the arrays. We can get that from the index path. Since this app has only one section, you can consider only the row. Add this to the method’s code:

let row = indexPath.row

This give us the row number in the table, and the index for the arrays. To set titleLabel with the menu item, add this

cell.textLabel?.text = menuItems.names[row]

To set the price in the detail, add this:

let price = String(format:"%2.2f", menuItems.prices[row])
        cell.detailTextLabel?.text = price

The app will highlight specials in green by changing the background color of the cell. Add this:

if menuItems.specials[row]{
            cell.backgroundColor = UIColor.green
        } else {
            cell.backgroundColor = UIColor.white
        }

Finally return the cell

return cell

Build and run. You have a table you can scroll through.
2016-10-02_13-55-11

This is only the beginning of tables. There’s a lot more to explore. Once you got this small last of how to build a table you might want to check out a few more tutorials on tables. Next you should dive a little deeper into tables with this post.

The Whole Code

Here is the code for this lesson. You can also download the completed project here:pizza table.zip

MenuItems.swift

//
//  MenuItems.swift
//  SwiftTableViewDemo
//
//  Created by Steven Lipton on 10/1/16.
//  Copyright © 2016 Steven Lipton. All rights reserved.
//

import UIKit

class MenuItems:NSObject{
    let names:[String] = [
        "Margherita Pizza","BBQ Chicken Pizza",
        "Pepperoni Pizza","Sausage Pizza",
        "Seafood Pizza","Sausage Deep Dish",
        "Meat Lover's Deep Dish","Veggie Lover's Deep Dish",
        "BBQ Chicken Deep Dish","Mushroom Deep Dish",
        "Tiramisu","Vanilla Ice Cream",
        "Apple Crostata","Hot Fudge Pizza",
        "Soft Drink","Coffee",
        "Espresso","Mineral Water"]
    let prices:[Double] = [
        7.95,11.49,
        8.45,8.45,
        12.75,10.65,
        12.35,10.00,
        16.60,11.25,
        6.50,2.25,6.50,
        9.75,1.25,
        1.25,3.50,3.75
    ]
    let specials:[Bool] = [
        false,true,
        false,false,
        false,false,
        true,false,
        false,true,
        false,false,
        false,true,
        false,false,
        true,false]
}

TableViewController.swift

//
//  TableViewController.swift
//  PizzaTable
//
//  Created by Steven Lipton on 10/2/16.
//  Copyright © 2016 Steven Lipton. All rights reserved.
//

import UIKit

class TableViewController: UITableViewController {
    var menuItems = MenuItems()
    
    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return menuItems.names.count
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        let row = indexPath.row
        cell.textLabel?.text = menuItems.names[row]
        let price = String(format:"%2.2f", menuItems.prices[row])
        cell.detailTextLabel?.text = price
        if menuItems.specials[row]{
            cell.backgroundColor = UIColor.green
        } else {
            cell.backgroundColor = UIColor.white
        }
        return cell
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()

      }
}

Why do we need Delegates in iOS and WatchOS?

About two years ago someone asked me a very good question: Why do we need delegates for UIViewControllers?  He thought Swift  made things easier, but this delegate stuff seems very complicated. Shouldn’t we be able to send a message or initializer between classes?

When I first learned iOS, I’ll admit it took me months to understand what happened with delegation. I found lots of confusing code and little explanation. AS I was researching some more preferences to send people to, I found the results lacking. Most often, tutorials refer to how to use an Apple factory delegate, not making your own callback. Its these callbacks which require full knowledge of delegates.

I decided it was time to update this, and to include two examples developers might run into: the iOS and watchOS versions. With the maturing of watchOS in watchOS 3 I think more developers might begin to look at developing watch apps, and there’s some twists there that might cause some confusion.

Let’s start at the beginning, so everyone understands the problem.

What is a Class?

Let’s start at the beginning, so everyone understands the problem. While we use classes in object-oriented programming, it’s good to review what they actually are. A class is a collection of data, which we call properties, and actions we can do to those properties, which we call methods.

Properties and methods are either public or private. A public method is one that classes other than the defining class can see and can use. Private means that the property or method is only usable and visible within the defining class. Other classes cannot see or use it. In Swift the private keyword makes properties and methods private. Swift’s calculated properties feature is another way to make properties private. In Swift, there is also a default state which makes a method or class public to the current target, but not other targets.

We tend not to like other people messing with our insides, and that is a good programming practice too. In general, it is best to leave what is public by other classes to a necessary minimum. Keeping properties and methods private and not exposing all of our class is known as encapsulation.

Encapsulation allows us to make code as modular as building blocks. Just as a few stubs come out of an otherwise standard sized brick, only a few usable methods come out of a class. Then they can attach to a lot of other bricks.

What is  Model –  View – Controller  or MVC?

MVC schematic blankA term heard often  when working with Xcode, is MVC. MVC stands for Model-View-Controller. It is not an exclusive term to Xcode projects. It is a pattern of programming, a good organization of any program or application in a graphics-rich environment, and arguably any environment that interacts with the user. MVC separates the major parts of an application. First it separates the data and the user interaction then adds an intermediary between them. Why is this important? You might write and publish an application for an iPhone, then decide an iPad version would be a good idea, then decide to make a watch version. With MVC, you only change one part completely, the view and possibly some of the controller. The code handling your data never changes between the versions saving a lot of time and effort.

What is a Model?

MVC schematic modelThere are parts of our program that deal with information we want to process. A pizza ordering system has a list of data giving us information about each person’s order. There may be other links to that data with more data about each customer, and about each pizza. In a pizza ordering system this is our model: the collection of all the data we will use in our ordering system. It does not in any way interact with the user. It does not display anything or does it ask for input. It is just data. Here is an example of very simple model:

class switchState{
    var state:Bool
    func textState()->String{
        if state {
            return "On"
        } 
        return "Off"
    }
    func overLoadSwitch(users:Int,load:Int){
      let totalLoad = users * load 
      if totalLoad > 100{
          switch = false
      }
}

This model is the state of a switch.  That’s the data. the model has two methods. textState(), describes the state of the switch as a string,  overLoadSwitch() turns off the switch if users multiplied by load is greater than 100 . There is a lot more methods I should add to describe the switch, but any method is changing or describing data only. There is no user input or output here. Models might make calculations but again there is no user interaction here.

What is a View?

MVC schematic viewWhere all the user interaction happens is in the view. In Xcode, most people use Interface Builder either as a scene in a storyboard or a .xib file to build their views.  A developer can programmatically create a view class to hold the different controls.

2016-08-01_07-11-48As the model never interacts with the user,  the view never interacts directly with the data. The view doesn’t do much but sit there. It might respond to a user touch with feedback such as a notifying a method somewhere, a color change when a button gets tapped or a scrolling motion at times, but that is all it does. The view does contain a lot of properties and methods and that tell us the state of the view. We can change the appearance and behavior of the view through methods and properties. The view can tell the controller that there was a change in the view, such as a button getting pressed, or a character typed. it can’t do anything about it, but it can broadcast something.

What is a Controller?

MVC schematicThe heart of MVC connects these two. Called the controller or view controller, it coordinates what happens in the model and what happens in the view. If a user presses a button on the view, the controller responds to that event. If that response means sending messages to the model, the view controller does that. If the response requires getting information from the model, the controller does that too. in Xcode, @IBOutlet and @IBAction connect Interface Builder files containing views to the view controller.

The key to MVC is communication. To be more accurate, the lack of communication. MVC takes encapsulation very seriously.  The view and the model never directly talk to each other. The controller can send messages to the view and the controller. The view and controller may do an internal action to the message sent as a method call or it may return a value to the controller. The controller never directly changes anything in either the view or the model.

So to summarize, a view, a model and a controller cannot directly change a property in each other. A view and a model may not talk to each other at all. A view can tell the controller there is a change in the model. A controller can send messages in the form of method calls to the view and the model and get the responses back through that method.

MVC schematic full annotated

How Does MVC Connect to Other MVC’s

What we’ve discussed so far is for only one scene in a much larger application. Suppose I have the following  watchOS storyboard:

2016-09-21_05-01-58

I have an a button Switch which loads a second face that has a switch.  When I decide which way I want the switch, I press done.

The Easy Direction

In Xcode we have what are known as segues. Segues are a convenience to point from one view controller to another.  When segues keep track of some things that would become cumbersome to control ourselves in a simple way. When we move from one controller to the next, the segue tells the system to open this particular view controller, which then opens up a view and model. The model and view in the new MVC setup is different then the calling one. Apple includes a method prepare(for segue:) for  iOS which give us a chance to set values in the new view controller,  and subsequently the new view controller’s view and model.

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "switch"{
         let vc = segue.destination as! SwitchViewController
         vc.switchState = false
        }

With the introduction of WatchOS came a slightly different approach.  instead of having the full model available,  watchOS sends to new controllers a single value called context. As this is type Any?,  you can put whatever you want in this value. Most often developers send dictionaries of values to other controllers through the contextForSegue method. When the destination application wakes up. the awake method  converts the context to the proper type and assigns it correctly.

override func contextForSegue(withIdentifier segueIdentifier: String) -> Any? {
        return self
    }

For both a identical  phone or watch app I could press the Switch button.  It launches  the switch face and  pass a value to the switch to be false.

The Problem Direction

We can turn the switch off and on easily enough.  But when we press Done to send it back to the original controller  is when problems show up. By the rules of MVC, we need a method to return a value. Where in a called instance can we go back to the class calling it? With an encapsulated class we can’t. There is no way to send that revised model back to the original controller without breaking encapsulation or MVC. The new view controller does not know anything about the class that called it. We look stuck. If we try to make a reference directly to the calling controller, we may cause a reference loop that will kill our memory. Simply put, we can’t send things backwards.

This is the problem that delegates and protocols solve by being a little sneaky. Imagine another class, one that is really a skeleton of a class. This class contains only methods. It declares that certain methods are in this class, but never implements them. In Swift they are protocols. We make a protocol class that has one method. That method is what you do when you are done  with the switch, and want to go back to the calling controller. It has a few parameters, things you want to pass back to the calling view controller.  So it might look like this:

protocol SwitchDelegate {
    func didFinishSwitch(switchState:Bool)
}

I passed back the state of the switch in this case.

In the controller with the switch, we make an instance of this protocol, calling it delegate.

delegate:SwitchDelegate! = nil

Since we have a property of type SwitchDelegate, we can use the methods of the SwitchDelegate type, In our example, that is our method didFinishSwitch. We can stick that method call in a action for a Done button:

@IBAction func doneButtonPressed(sender:UIButton!){
    delegate.didFinishSwitch(switchState: switchState)
    dismiss(animated: true, completion: nil)
}

or for WatchOS

@IBAction func submitSwitchStatus() {
    delegate.didFinishSwitch(switchState: switchState)
    pop()      
}

Since protocols are skeletons, it means any other class can adopt them. A class makes the protocol methods part of its own class with a stipulation. As soon as a protocol gets adopted, you need to flesh out the skeleton. The developer has to code the required methods in the adopted class’ code. We adopt a protocol by placing it after the name of the class and superclass. For iOS you might have

class OrderPizzaViewController:UIViewController,PizzaEditDelegate

and for watchOS, you might have

class InterfaceController: WKInterfaceController,SwitchDelegate {

As soon as you do that, you will get a compiler error since the protocol’s method does not exist in the class. In the code for the adopting class, in our example OrderPizzaViewController, we would implement the method

func didFinishSwitch(switchState: Bool) {
        if switchState {
            textState = "Switch is On"
        } else {
            textState = "Switch is Off"
        }        
    }

We get the data back, and what we need with it, in this case a string that we’ll print to the label.
One more step. While back in the destination controller, I said the delegate was an instance of the protocol, I didn’t say where the delegate was. In prepare(for Segue) I add one more line vc.delegate = self saying the protocol is your controller

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "switch"{
         let vc = segue.destination as! SwitchViewController
         vc.switchState = false
         vc.delegate = self
        }

In WatchOS this gets a bit trickier. I have only one context to pass both the switchState and the delegate. For multiple values generally developers use a dictionary like this:

override func contextForSegue(withIdentifier segueIdentifier: String) -> Any? {
        let context:[String:Any] = ["switchState":false,"delegate":self]
        return context
    }

the awake method would have code to unwrap the dictionary and assign the values.

When we tap Done in a watch or phone application, the method runs, it knows it is located in the calling controller, and calls it there where we added to the original class.The data is a parameter so the program can easily transfer into the controller and to the model. Delegates and protocols are bit sneaky but it works, and is one of the most important techniques when working with view controllers.

mvc-schematic

The original question asked why didn’t Swift make this simpler. As I hope I’ve shown here with a Swift context, it doesn’t matter what object oriented language you use. Delegates are part of the MVC pattern, which is a good programming practice.

Understand and Use Closures in Swift

Have you ever seen some factory method in UIKit and see this strange parameter called completion or completionHandler? Usually you put nil there and leave it alone. These strange things like (Double,Double) -> Bool things are closures. Closures are functions you use as types, often in parameters of other functions. In this lesson we’ll explore closures and get under the hood to explain what they are and what they are really doing.

Set Up a Playground

Set up a playground in Xcode, the iPad or on the web at the IBM Swift Sandbox. IF using the IBM Swift Sandbox, make sure you have Foundation imported.

import Foundation

The Basics of Closures

Suppose I want to calculate the volume of a deep dish pizza. Add these functions to the playground:

 //area of a round pizza
    func roundArea(radius:Double) -> Double{
        return M_PI * radius * radius
    }
    //volume of a round pizza
    func roundVolume(height:Double, radius:Double ) -> Double{
        return roundArea(radius: radius) * height
    }

Add a variable to compute the volume of a pizza of radius 6 and height 2, then print it

var volume = roundVolume(height:2,radius:6)
print( String(format:"Round volume %4.2f",volume))

Run this and get the volume from the area on the console. Which is fine if I had only round pizzas. What if I had rectangle, oval or triangle pizzas? I’d have to write two new functions each: one for the area and one for the volume. However in each case I’m only changing the area calculation. What if I could pass just the calculation to the volume function? That’s what a closure is: a way of writing something like a function but assigning it as a type. Add the function to the class.

func volume(
    height:Double, 
    dim1:Double,
    dim2:Double, 
    area:(Double,Double) -> Double) -> Double
    {
        return area(dim1,dim2) * height
    }

Look at the parameter area. I’ve declared it (Double,Double) -> Double. That looks a lot like a function that returns Double, and two Double parameters. That’s what a closure does as a type. A closure gives a skeletal structure like a function you can pass as a parameter. Below the volume function add the following line of code.

let rectangleArea = { (length:Double,width:Double) -> Double in
    return length * width
}

When I declare the contents of the identifier, I flesh out something like a function inside of curly braces. Instead of func before the parameters, I put in after the return type. There are parameters (length:Double,width:Double). I have the return type as a Double. For closures, there must always be a return value. If you don’t have one mark it Void or ().

Since I declared the type in the closure declaration, I often can remove it from the declaration

        
let  rightTriangleArea = {(length,width) -> Double in
    return length * width / 2.0
}  
let ovalArea = {(length,width)->Double in
    return length/2.0 * width/2.0 * M_PI
}

It doesn’t work in all cases though. This give an error if you do not specify the type

let roundSliceArea = { (radius:Double, slices:Double) ->Double in
    return M_PI * radius * radius / slices
}

I can use the same volume function and change how I compute the area.

print (volume(height: 2,dim1: 10, dim2: 12, area:rectangleArea))
print (volume(height: 2,dim1: 10,dim2: 12, area:roundSliceArea))
print (volume(height: 2,dim1: 10, dim2: 12, area:rightTriangleArea))
print (volume(height: 2,dim1: 10, dim2: 12, area:ovalArea))

I do have a problem with a circle. I could define it like this in my storyboard:

 let circleArea = {(radius)->Double in
            return radius * radius * M_PI
 }
print (self.volume(height: 2,dim1: 10, dim2: 12, area:circleArea))        

This doesn’t work for the circle, because the number of parameters are different. You’d get this error message
Cannot convert value of type '(Double) -> Double' to expected argument type '(Double, Double) -> Double'

You have choices: Use the oval with the same length and width or a placemarker.  I tend to choose the place marker. Change circleArea to add the extra parameter. Fix the above code to this:

let circleArea = {(radius:Double, placeMarker:Double) -> Double in
    return M_PI * radius * radius 
}
print (volume(height: 2,dim1: 10, dim2: 12, area:circleArea))

Literal Closure in Parameters

You don’t have to assign the closure to a constant. You can write it explictly in the function. For a rectangle area, you can write this in the playground.

 
volume = volume(
    height: 2,
    dim1: 10,
    dim2: 12,
    area: {(width,length)->Double in
        return width * length
    }
)
        print(volume)

You’ll find this a very common way of specifying the closure. When the closure is the trailing parameter, you can place it after the function like this:

volume =  volume(
    height: 2,
    dim1: 10,
    dim2: 12) 
    {(radius,placemarker)->Double in
        return M_PI * radius * radius
    }
print(volume)

Closures as Completion Handlers

One very common use of closures is completion handlers. Make a new function like this:

func volume(
    height:Double,
    dim1:Double,
    dim2:Double,
    completionHandler:(Double)->()
){
    let result = dim1 * dim2 * height
    completionHandler(result) 
}

Neither the completionHandler closure nor the volume function returns anything. Instead the result is the parameter of the completion handler.
Why would anyone do this? The reason is asynchronous processing. There are methods which Apple or the developer don’t want to run in the main thread. If you are querying a database, or opening a file any results appear in a closure. The database query might take some time, and you don’t want the rest of your application to freeze while you wait for the result. Similarly, while loading a file you don’t want to freeze the system waiting to learn if the load was successful.
Instead of return in these functions, the method runs on another thread at its own pace and lets the main thread go on its merry way. When done, the method calls something like completionHandler, handler, or completion with the results it returns as the completion parameter.

The developer uses the result their implementation of the completion handler. This is why most often closures happen completely within a function call. Usually they are specific to the code around it. For example, the volume function with the completionHandler would code like this to save the result to the volume property and output the result.

volume(height: 2,dim1: 10,dim2: 12)
{(result)->() in
    print(result)
    volume = result  //in a class use self
    resultLabel.text = String(format:"Completion %5.2f")
}

Completion handlers often pass off the value to a property in a class, like the code above assigns the value of  result to volume. If you run the code above within a class, be sure to include the class identifier or self. volume = result should be self.volume = result. The identifiers within a closure have no scope to the class. They must be explicitly stated.

A Real Example of a Completion Handler

As a general rule, you’ll find completion handlers when you don’t know when you will complete a task. One good example of this is presenting alert views.

Set up a new single view project named ClosureDemo, with Swift as the language. Go to the storyboard and drag a label and button.

Set the font on both to Title 1.  Select the button. Title the button Alert. Click the alignment iconalignment icon in the auto layout menu bar. Check Horizontally in Container and Vertically in container.  Change Update from to Items of new constraints like this:

center alignment

Click Add 2 constraints.  Select the Label. Title it Results.  Click the pin icon pinMenuButton in the auto layout toolbar.  In the dialog box that appears type 10 then tab, 10 then tab and 10 then tab. Click down to the bottom and Update frames with Items of New Constraints.

2016-09-02_07-07-01

Click Add 3 constraints.

Open the assistant editor and control-drag the label to the code. Name the outlet resultsLabel. Control-Drag from the button to the code. Change to an action. Name the action presentAlert.

Close the Assistant editor.  Open the Viewcontroller.swift code.

In the presentAlert action, add the following code:

 @IBAction func presentAlert(_ sender: UIButton) {
     volume = 240.0
 //example of a real completion handler.
     let alert = UIAlertController(
         title: "Alert",
         message: "Volume is \(volume)",
         preferredStyle: .alert)
   

Alert actions only activate after the alert shows and the action’s button gets tapped by the user. The UIAlertAction initializer uses handlers to describe the action when pressed. Add this to the compute action:

   
let clearAction = UIAlertAction(
    title: "Clear", style: .destructive,
    handler: {(action)->() in
        self.volume = 0
        self.resultLabel.text = "Cleared"
    }
)
 

In clearAction, the user sets the volume property to 0 and reflects that in the Label.  Again, the closure is independent of the scope of its class. You must specify self in order to use the ViewController classes’ properties and methods.

Add two more examples of actions:

       
let doubleAction = UIAlertAction(
    title: "Double",
    style: .default,
    handler: {(action)->() in
        self.volume *= 2
        self.resultLabel.text = "\(self.volume)"
    })
let cancelAction = UIAlertAction(
    title: "Cancel",
    style: .cancel,
    handler:{(action)->() in
       self.resultLabel.text = "\(self.volume)"
    })
   

Add the actions to the alert

alert.addAction(clearAction)
alert.addAction(doubleAction)
alert.addAction(cancelAction)

Finally present the alert controller. present has a completion handler. Add a print statement to it to see it in action, then a print after the present.

 
present(alert, animated: true, completion: 
{()->Void in
    print ("present Completed")
 })
 print ("Outside Handler")

Build and run. Tap the Alert button. You get the alert. The console printed this:

Outside Handler
present Completed

After calling present, The system executed the next step, and did not wait for it to finish printing  Outside Handler. Once the presentation completed, the system printed present Completed. The alert shows:

2016-09-12_06-03-57

Tap the double button. The label reads 240. Try the other buttons.

2016-09-12_06-04-38

You’ll find closures in most often in these handlers. Anything that takes and unpredictable amount of time will use a handler in a closure.

The Whole Code

You can find the code for this tutorial on the IBM Swift Sandbox. For cutting and pasting into an Apple Playground on iPad or Xcode, Use the code below.

//
// Closure Demo file 
// For MakeAppPie.com  closure tutorial 
// Sep 2016 by Steven Lipton 
// 
//
import Foundation

 //area of a round pizza
    func roundArea(radius:Double) -> Double{
        return M_PI * radius * radius
    }
    //volume of a round pizza
    func roundVolume(height:Double, radius:Double ) -> Double{
        return roundArea(radius: radius) * height
    }
    var volume = roundVolume(height:2,radius:6)
print( String(format:"Round volume %4.2f",volume))

//Closure to change the area formula
func volume(
    height:Double, 
    dim1:Double,
    dim2:Double, 
    area:(Double,Double) -> Double) -> Double
    {
        return area(dim1,dim2) * height
    }
    
    //Assigning type (Double,Double) -> Double to Classes
    
    let rectangleArea = { (length:Double,width:Double) -> Double in
    return length * width
}
let  rightTriangleArea = {(length,width) -> Double in
    return length * width / 2.0
}  
let ovalArea = {(length,width)->Double in
    return length/2.0 * width/2.0 * M_PI
}
let roundSliceArea = { (radius:Double, slices:Double) ->Double in
    return M_PI * radius * radius / slices
}
//Trying out the volume function

print (volume(height: 2,dim1: 10, dim2: 12, area:rectangleArea))
print (volume(height: 2,dim1: 10,dim2: 12, area:roundSliceArea))
print (volume(height: 2,dim1: 10, dim2: 12, area:rightTriangleArea))
print (volume(height: 2,dim1: 10, dim2: 12, area:ovalArea))

//Fitting a single parameter formula with a placemarker
let circleArea = {(radius:Double, placeMarker:Double) -> Double in return M_PI * radius * radius }
print (volume(height: 2,dim1: 10, dim2: 12, area:circleArea))
// closure within parameters
        volume = volume(height: 2, dim1: 10, dim2: 12, area: {(width,length)->Double in return width * length})
        print(volume)
// Trailing closure outside parentheses
volume =  volume(height: 2, dim1: 10, dim2: 12) {
     (radius,placemarker)->Double in
          return M_PI * radius * radius
}

//Closures as Completion Handlers
func volume(
    height:Double,dim1:Double,dim2:Double,
    completionHandler:(Double)->()
){
    let result = dim1 * dim2 * height
    completionHandler(result) 
}

// For asynchronous processing, use the closure instead of returning the result. 
volume(height: 2,dim1: 10,dim2: 12)
{(result)->() in
         print(result)
         volume = result
         
}

The ClosureDemo Alert project

This is the code for the ClosureDemo Alert project. Add the label and button as described above than connect to this code in ViewController.

//
//  ViewController.swift
//  ClosurePlay
//
//  Created by Steven Lipton on 9/9/16.
//  Copyright © 2016 Steven Lipton. All rights reserved.
//

import UIKit

class ViewController: UIViewController {
    
    var volume = 0.0
    
    @IBOutlet weak var resultLabel: UILabel!
    @IBAction func compute(_ sender: UIButton) {
        volume = 240.0
        //example of a real completion handler.
        let alert = UIAlertController(
            title: "Alert",
            message: "Volume is \(volume)",
            preferredStyle: .alert)
        
        let clearAction = UIAlertAction(
            title: "Clear", style: .destructive,
            handler: {(action)->() in
                self.volume = 0
                self.resultLabel.text = "\(self.volume)"
        })
        
        let doubleAction = UIAlertAction(
            title: "Double",
            style: .default,
            handler: {(action)->() in
                self.volume *= 2
                self.resultLabel.text = "\(self.volume)"
        })
        let cancelAction = UIAlertAction(
            title: "Cancel",
            style: .cancel,
            handler:{(action)->() in
                self.resultLabel.text = "\(self.volume)"
        })
        
        
        alert.addAction(clearAction)
        alert.addAction(doubleAction)
        alert.addAction(cancelAction)
        present(alert, animated: true, completion: {()->Void in
            print ("In present Handler")
        })
        print ("Outside Handler")
        
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
    }
    
    
}

Make a WatchOS 3 Haptic Catalog with a Picker

How does the Apple Watch communicate to the user when they are not looking at the watch face? That is done with haptics. Haptics are sounds and taps letting the user know something is happening. In this lesson, I’ll explain to you how to use haptics in Watch OS applications by creating a catalog of all the haptics using a WatchOS picker.

The picker control is an object for selection of multiple items. You can use the picker to display either full-screen images or text for selection. In this lesson, I’ll keep it simple with a text-based picker.

Make a New Project

Create a new WatchOS project called HapticPickerDemo. Use Swift as the language, uncheck Notifications, and keep the device Universal.  Open the interface.storyboard file in the WatchKit App group.

Find the picker in the object library. Drag a picker to the interface.

2016-08-27_07-01-54

With the picker selected you’ll see four attributes of a
picker.  The Focus Style and Indicator give you visual elements to highlight the picker. The most important attributes are Style and of course Enabled. You have three style choices: List, Stack and Sequence. List is a text-based picker. Stack and Sequence is an animated and non-animated image picker.

2016-08-27_07-09-18

Set your attributes to the illustration above.  Set the picker’s Style  to List. Set the Focus Style to  Outline with Caption. This will show an outline around the picker with a caption at the top. This caption is context sensitive to the picker selection. If you’ve set a complication on a watch, you are familiar with this focus style, such as  the black on green lettering  for weather in this setting:

2016-08-27_07-02-50

From the Object Library, add  a button under the picker. Title the button Play Haptic.

2016-08-27_07-04-29

Close the attributes and navigation panels. Open the assistant editor.

Make an outlet for the picker by control dragging from the picker to the InterfaceController class

@IBOutlet var picker: WKInterfacePicker!

Make an action for the picker’s action,changing Outlet to Action in the popup after you control drag.

 func pickerDidChange(_ value: Int) {
    }

Make an action for the button’s action, changing Outlet to Action in the popup after you control-drag.

 func playHaptic(_ value: Int) {
    }

Playing a Haptic

There’s two parts to a haptic you need to know. There is a play function [in WatchOS 2 playHaptic()]  you call on the current device object called by
WKInterfacedevice.current()object [in WatchOS 2 WKInterfaceDevice.currentdevice() ]. The play method has one parameter of type WKHapticType, which is an enumeration of haptic types.

  • notification tells the user there is a notification,
  • directionUp indicates an upward value,
  • directionDown indicates a downward value,
  • success indicates the successful completion of a task,
  • failure a failed task,
  • retry tells the user to retry,
  • start the beginning of an action,
  • stop the end of an action,
  • click is a very slight click, which you probably won’t hear but probably feel on a watch.

Close the Assistant editor.  Go to InterfaceController.swift in the App extension group. To make the button play a .success haptic change the playHaptic action to this:

 
func playHaptic(_ value: Int) {
    WKInterfaceDevice.current().play(.success)
}

Build and run using the 38mm simulator. Press the Play Haptic Button and  you get a sound.

In the simulator, you don’t get the taps you’ll get if you were using the watch. If you have a watch, run this on your watch and you’ll feel the tap.

Implementing the Picker

There is no documentation on what the taps feel like. It’s hard to describe in words,you have to feel it. In the rest of this lesson we’ll use WatchKit’s WKInterfacePicker to make a selectable catalog of haptics you can run on an Apple Watch.

Pickers have one parameter. Since pickers hold the list in a sequence, the parameter value is the index of that sequence. Delete all life cycle methods but willActivate. Add the list of haptic types exactly in the order above for the picker as an array.

let titles = [
    "notification","directionUp",
    "directionDown","success",
    "failure","retry",
    "start","stop","click"
]

Pickers will not use these arrays directly. Pickers get their selections from a WKPickerItem object. Code will create an array of WKPickerItem, and set that as the picker’s items. WKPickerItem has several properties to make the picker flexible.

  • title – A String? to use in a list
  • caption – A String? used as a caption for item in a list
  • accessoryImage – A Small WKImage? to display next to title in a
    list or as an alternate to text as in small complication setting.
  • contentImage – In a Stacked or Image Sequence style, a
    WKImage?

The picker has a setItems method which takes the array of picker
items to make the list, stack, or sequence of images, depending on the display style. For every picker you create, you build a function that iterates through the arrays, adding the elementsts as pickerItems. Add a function refreshPickerItems:

 func refreshPickerItems(){
 }

Add an empty array of picker items to the function.

 
func refreshPickerItems(){
    var pickerItems:[WKPickerItem] = []
}

Add a loop iterating through the titles.

 
func refreshPickerItems(){
    var pickerItems:[WKPickerItem] = []
    for item in titles{
    }
}

In the loop creates an instance of WKPickerItem. Add to pickerItem the title  from the corresponding element of the arrays. Add the literal caption Haptic. (If you want to experiment, with captions, try coding it as "Haptic-" + item ) Add the picker item to the pickerItems array.

func refreshPickerItems(){ 
    var pickerItems:[WKPickerItem] = [] 
    for item in titles{ 
        let pickerItem = WKPickerItem()
        pickerItem.title = item
        pickerItem.caption = "Haptic"
        pickerItems += [pickerItem]
    }
}

Once the pickerItems array is complete, set the items in the picker.

func refreshPickerItems(){ 
    var pickerItems:[WKPickerItem] = [] 
    for item in titles{ 
        let pickerItem = WKPickerItem()
        pickerItem.title = item
        pickerItems += [pickerItem]
    }
    picker.setItems(pickerItems)
}

In willActivate, call this function to refresh the list.

override funcwillActivate() {
    super.willActivate()
    refreshPickerItems()
}

Selecting a Picker Entry

If you were to run the project now, you would see the picker displayed correctly. You could not select anything though. That happens in the action. The pickerDidChange action has a Int parameter value, which is the current index on the picker.

I told you earlier to be careful getting the order correct in the titles  array.  This is why. Since WKHapticType is a enum you can select the type by the rawValue of the enum. That raw value matches the value parameter. Before we try this, add a property hapticType to store the type.

varhapticType:WKHapticType = .notification

I’ve initially set this to .notification. In the pickerDidChange action set the hapticType property with the raw
value we can get the value parameter.

@IBAction func pickerDidChange(_ value: Int) { 
    hapticType = WKHapticType(rawValue:value)!
}

Playing the Haptic

The last step is to play the haptics. To the action  pickerDidChange  add a .click haptic

WKInterfaceDevice.current().play(.click)

This demonstrates one use for haptics, feedback to the user.  In the action playHaptic, change the .success haptic to the property hapticType

 @IBAction fund playHaptic() {
        WKInterfaceDevice.current().play(hapticType)
    }

Run in the 38mm simulator. Select a haptic and press Play Haptic. You’ll hear the chime for it.

If you have a watch, load it on your watch, and try the application. When you tap Play haptic on the watch you will get the watch tap as well.

Don’t over use Haptics. Unless your app is an interval timer, don’t  have one go off every second or minute. That just gets annoying. Use haptics at the right times to attract a user’s attention to their Apple watch or give instant feedback.

The Whole Code

//
//  InterfaceController.swift
//  HapticPickerDemo WatchKit Extension
//
//  Created by Steven Lipton on 8/26/16.
//  Copyright © 2016 Steven Lipton. All rights reserved.
//

import WatchKit
import Foundation


class InterfaceController: WKInterfaceController {

    @IBOutlet var picker: WKInterfacePicker!
    
    //List of WKHapticType in rawValue order
    let titles:[String] = [
        "notification","directionUp",
        "directionDown","success",
        "failure","retry",
        "start","stop","click"]
    
    var hapticType:WKHapticType = .notification
    
    //Use the index from the picker as the rawValue for the WKHapticType
    @IBAction func pickerDidChange(_ value: Int) {
        hapticType = WKHapticType(rawValue: value)!
        WKInterfaceDevice.current().play(.click)
    }
    
    
    @IBAction func playHaptic(){
        WKInterfaceDevice.current().play(hapticType)
    }
    
    
    func refreshPickerItems(){
        var pickerItems:[WKPickerItem] = []
        for item in titles{
            let pickerItem = WKPickerItem()
            pickerItem.title = item
            pickerItem.caption = "Haptic"
            pickerItems += [pickerItem]
        }
        picker.setItems(pickerItems)
    }
    
    override func willActivate() {
        // This method is called when watch view controller is about to be visible to user
        super.willActivate()
        refreshPickerItems()
       
        
    }

}

How to Make a Tab Bar Controller in Swift 3.0 Code

While Navigation controllers often have the limelight when it comes to Xcode’s view  controllers, tab bar controllers are better for independent tasks in the same app, or for different ways of working with the same model. In this lesson we’ll take a look at  how to make them in Swift programmatically. If you are interested in tab bar controllers on the storyboard, You might want to read this post. For passing data between tabs read here.

Setting Up

While there are very easy storyboard ways of making tab bar controllers, we can do much of this programmatically. Start with a single view template and create a Swift project called TabProgDemo.  Once the project loads, on the keyboard hit Command-N. Create a  Cocoa Touch Class named PizzaViewController, subclassing of UIViewController.Make the language Swift, and check the mark to make a Xib file for an iPhone like this:

2016-07-12_10-38-48

Press Command-N again and Make another Cocoa Touch Class like the first, subclassing UIViewController. Name it PieViewController again do not creating a XIB file.

2016-07-13_06-44-57

I have created a file of image assets for this lesson. You can get them here as a zip file  or you can right click and save  the images below:

Pie Iconpizza icon

pizza_bar_icon@2xpizza_bar_iconpie_bar_icon@2xpie_bar_icon

Save these images on your drive. Open up your Assets.xcassets folder in Xcode. Select all the files in finder and drag them into the assets folder.

2016-07-13_06-15-30

Go to the the PieViewController.xib file. Make sure in the lower left of Interface builder it reads  the default setting:

view as 6s

 If, not set it to iPhone 6s by clicking it and selecting the device.  Set the background color to Light Green(#AAFFAA). Drag out a label and title it Pie at 32 points. Add the color Pie Icon. Your XIB should look like this:

2016-07-13_06-46-52

Select the PizzaViewController.xib file. Set up the Xib the same way as the pie controller. Use a Light Red(#FFAAAA) for the background:

2016-07-13_06-30-30

Tab Bar Programmatically

Click open the AppDelegate.swift file. While much of this can be important stuff, we’ll clear it out so we can concentrate on tab bar controllers. Replace the class with the following:

class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow?
    func application(application: UIApplication,
                      didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
        return true
    }
}

Let’s put this code together part by part. First add this under the function declaration:

let tabBarController = UITabBarController()

Creates an instance of a UITabBarController. This will be the controller we’ll configure in this function. We are doing this here so it is global to the application, one of the few times you want to do something globally.

Create the two view controllers from the XIB files. In full accordance with the adage “Life is uncertain, eat dessert first”, we’ll make the first page on launch be the pie page.

let tabViewController1 = PieViewController(
    nibName: "PieViewController",
    bundle: nil)
let tabViewController2 = PizzaViewController(
    nibName:"PizzaViewController",
    bundle: nil)

Add these three lines:

let controllers = [tabViewController1,tabViewController2]
tabBarController.viewControllers = controllers
window?.rootViewController = tabBarController

UITabBarController has a property called viewControllers, which is an array of the view controllers in the order displayed in the tab bar. Our first line of this segment makes an array of view controllers in the order we want them to present. Next we assign the array to the tab bar controller. The last line assigns the controller as the root view controller.

We have our controller set up, but no titles or icons. This code assigns the title and image.

tabViewController1.tabBarItem = UITabBarItem(
    title: "Pie",
    image: UIImage(named: "pie_bar_icon"),
    tag: 1)
 tabViewController2.tabBarItem = UITabBarItem(
    title: "Pizza",
    image:UIImage(named: "pizza_bar_icon") ,
    tag:2)

Each view controller has a property tabBarItem which contains the icon and text for the tab bar. We use the UITabBarItem(title:String,image:UIImage,tag:Int) initializer to create the tab bar items. In our example,  we set the first one to Pie and use the pie_bar_icon image  for the first. The second uses Pizza and the pizza_bar_icon  image.

Set your simulator to the iPhone 6s. Build and run. You get the Pie first:

 2016-07-14_05-35-42

You’ll notice the tabs the bottom. Tap the pizza tab.

2016-07-14_05-36-10

 

You have working tabs.

Programmatic Navigation View Controllers in Swift 3.0

Navigation controllers are the workhorse of  organizing view controllers. I’ve covered much of their use in other posts about MVC, segues and delegates. In this chapter, we’ll go through some of the Swift code for the Navigation controller.

The View Controller Stack

Navigation view controllers are stack based. The newest view controller is the visible one. It is on top of the last one we saw.
If you are not familiar with the stack data structure, it is useful to understand stacks and their nomenclature a little better. Stacks work a lot like a deck of cards that are face up.

2016-07-06_06-20-22

You can only see the top card. When you place a card on top of the stack, you push a card on the stack. When you remove a card from the stack and show the card below it, you pop it off the stack. We use the terms push and pop a lot to talk about stacks. The two major methods we’ll be talking about popViewController and pushViewController use this nomenclature to explain what they do.

Opening a View Controller in a Xib

Let’s look at a few ways to programmatically move through view controllers by pushing and popping to the navigation stack directly.
Start a new single view project in Swift called SwiftProgNavControllerDemo. Go into the storyboard. Make sure you have a iPhone 6s selected for View as: in the lower left of the storyboard”

2016-07-05_06-18-15

Select the blank view controller. Be sure to select the controller by clicking the view controller icon  icon and not the view. From the drop down menu select Editor>Embed in > Navigation Controller.
In the view controller, add a label and a button so your code looks like the diagram below. If you wish you can also color the background:

2016-07-06_07-49-58

Open the assistant editor. Control-drag the button and make an action for a UIButton called nextButton. Remove everything else from the class for now. Add the following two lines to the nextButton

let vc = TwoViewController(
     nibName: "TwoViewController",
     bundle: nil)
navigationController?.pushViewController(vc,
     animated: true)

Line 1 creates a view controller of class TwoViewController, using the XIB of the same name. Line 2 pushed the view controller on the navigation controller stack maintained by ViewController. Your code should look like this when done:

class ViewController: UIViewController {
    @IBAction func nextButton(_ sender: UIButton){
    let vc = TwoViewController(
        nibName: "TwoViewController",
        bundle: nil)
     navigationController?.pushViewController(vc,
        animated: true)
    }
}

We need another view controller as a destination. Press Command-N or click File>New>File… Choose a iOS source template of Cocoa Touch Class. Make the new file a subclass of UIViewController and name the file TwoViewController. We’ll work with a xib for our destination controller. Check on the option Also create XIB file.

2016-07-06_07-45-10

You will find a new xib in interface builder. Set it up to look like the illustration below.

2016-07-08_05-44-23

In the assistant editor, remove everything to have an empty class. Control-drag the Next button inside the TwoViewController class. Make an @IBAction method named nextButton  as an UIButton.  Add the following code to the nextButton() method:

let vc = ThreeViewController(
            nibName: "ThreeViewController",
            bundle: nil)
        navigationController?.pushViewController(vc,
                animated: true )

Your code should look like this:

class TwoViewController: UIViewController {
    
    @IBAction func nextButton(_ sender: UIButton) {
        let vc = ThreeViewController(
            nibName: "ThreeViewController",
            bundle: nil)
        navigationController?.pushViewController(vc,
            animated: true )
    }
}

Let’s do this one more time so we end up with three view controllers to push onto the view controller stack. Follow the same procedure as you did for TwoViewController, but name it ThreeViewController. Set the view to look like this:

2016-07-08_05-44-43

There’s no buttons here, so you have no actions to set. Change your simulator to iPhone 6s. Build and run. Tap the Next button and move between the three view controllers.

2016-07-06_08-25-30    2016-07-08_05-43-07    2016-07-08_05-43-43

Pushing a view controller from a  xib  is two lines of code:

let vc = ViewControllerName(nibName: "nameOfNib", bundle: nil)
navigationController?.pushViewController(vc, animated: true )

The first line creates the view controller. I tend to keep it simple and use vc, though if I had more than one, I’d be more descriptive.
Xibs are probably one of the most common uses for pushing a view controller. There are situations where you cannot use the storyboard and this is a good traditional alternative. Often self-contained reusable  modules will use a xib instead of a storyboard.

Programmatic Segues to View Controllers

For most uses, I prefer the storyboard over xibs for two reasons: first it is better documentation of the user interface. Secondly, I prefer to let the system do as much of the background work as possible by using the storyboard. The deeper into code you go, the more you have to worry about unexpected bugs.

We can programmatically push a view controller from a storyboard in two ways: segues or storyboard identifiers.  We’ll start with segues. One of the first ways anyone learns to use storyboards is direct segues, connecting up a button directly to a view. You can also do segues programmatically, which is useful when you conditionally go to a view.

Go to the storyboard. Add  two more view controllers to the storyboard. Label one View Controller Four and the other View Controller five.

2016-07-07_05-47-25

Click on the ViewController scene title in the storyboard. From the view controller Icon view controller iconon ViewController, control-drag from ViewController to somewhere on View Controller Four’s content so it highlights.

2016-07-07_05-55-32

Release the mouse button.  In the menu that appears, select Show.

2016-07-07_05-59-44

Click on the Show segue icon show segue icon to select the segue. Go into the properties inspector and set the segue’s Identifier to Four.

2016-07-07_06-03-18

Drag another button out to the View Controller scene and make the title Four.

2016-07-07_06-05-28

Go to ViewController class and add the following method:

@IBAction func fourFiveToggleButton(_ sender: UIButton){
    performSegue(withIdentifier: "Four",
        sender: self)
}

Open the assistant editor and drag from the circle next to the fourButton() method over the Four button and release.
The code above is a mere one line: it runs the segue. If you set the segue identifier correctly, that is all you need to do.

One use is conditional cases. Conditions in the current view controller or model might change. The app may display different view controllers based on those conditions. Let’s try a simple example. Just as we did with View Controller Four, make a segue with an identifier Five by control-dragging from the view controller icon view controller iconon View Controller One to the view of  View Controller Five.

2016-07-07_06-18-05

Select a Show segue. Select the segue by clicking the show segue icon show segue icon.  In the attributes inspector change the Identifier to Five.

Change the code for fourFiveToggleButton to this

@IBAction func fourFiveToggleButton(_ sender: UIButton){
    let normal = UIControlState(rawValue: 0) //beta 1 has no .normal bug#26856201
    if sender.titleLabel?.text == "Four"{
        performSegue(withIdentifier: "Four",
                     sender: self)
        sender.setTitle("Five", for: normal)
    } else{
        performSegue(withIdentifier: "Five",
                     sender: self)
        sender.setTitle("Four", for: normal)
    }
}

The code checks the contents of the title label. If the label is Four it goes to View Controller Four and changes the title label. If the label is Five, it goes to View Controller Five and toggles the label back to Four

Build and run.  we can toggle between the two views.

2016-07-07_06-44-06

An Interesting Stack Demonstration

Stacks are linear collections. How we compose that collection on the storyboard might be nonlinear. For example, View controllers four and five might both segue into view controller six.  On the storyboard drag out another view controller. Set a background color for it. Label it View Controller Six

 2016-07-08_05-55-47

For this example, we’ll use the storyboard directly. On View Controller Four, drag a Navigation Item. Title the navigation Item Four. Drag a bar button item to the navigation controller.  Title it Six

2016-07-08_05-57-26

Do the same for View Controller Five so the navigation bar looks like this:

2016-07-08_05-57-47

Control drag from View controller Four’s Six button to the Six View Controller. Select a Show Segue. Repeat for the  Five View Controller. Control drag from the Six button to the Six View Controller. Select a Show Segue.  Your storyboard now has this:

2016-07-08_06-06-24

We’ve set a storyboard where we go to Five or Four, and then go to six.  Build and run. We can go to Six from both view controllers.

2016-07-08_06-09-46

Closing a View Controller

Up to now, we’ve relied on the navigation controller’s Back button. Dismissal of view controllers with  popViewController() are common in an application. Almost every delegate between view controllers in a navigation stack will use it. There are several versions of the popping off controller for different uses.

Add two buttons to View Controller Six, titled Back and Root.

2016-07-08_06-14-23

Press Command-N to make a new class called SixViewController, subclassing UIViewController. Remove all the methods in the class.  In the SixViewController class, create an action  backButton:

 @IBAction func backButton(_ sender: UIButton) {
        navigationController?.popViewController(animated:true)
    }

You will get a warning  Expression of type 'UIViewController?' is unused. Ignore it for now, we’ll discuss it later.

Also in SixViewController,  add to the rootButton() method:

@IBAction func rootButton(_ sender: UIButton) {
  navigationController?.popToRootViewController(animated:true)
    }

Go to the story board and open the assistant editor. Drag from the circle next to backButton to the Back button. Drag from the circle next to the rootButton to the Root Button. Build and Run.  Go to Six. Press the new Back button. You go back to Four. Go to Six again and press the root button. You go back to One.

There are three versions of pop: popViewController(), popToRootController(), and popToViewController() The most Common is popViewController() which removes the top view controller from the stack. popToRootViewController() and popToViewController() pops everything or everything up to a specific view controller off the stack, returning what it popped off.

Because popViewController returns a value, we are getting the two warnings. We have to do something with the return value. You’ll notice in the error message that we get an optional returned.  If nil, there were no view controllers to pop off.  Use this to make sure you do have a navigation stack under the current controller. Change the class to this:

class SixViewController: UIViewController {
    @IBAction func backButton(_ sender: UIButton) {
        guard (navigationController?.popViewController(animated:true)) != nil
            else {
                print("No Navigation Controller")
                return
        }
    }
    @IBAction func rootButton(_ sender: UIButton) {
        guard navigationController?.popToRootViewController(animated: true) != nil
        else {
            print("No Navigation Controller")
            return
        }
    }
    
    }

By using guard and checking for nil the application checks to make sure there is a navigation stack. If not, code handles the error. If there is a segue set to Present modally by mistake and tries popping off the controller, the error gets handled. This is especially important in two situations: when you use a xib in a navigation controller and when you use a Storyboard ID. Both cases are independent of segues. Both can be used as a modal controller and a navigation controller. It’s likely you have modules set up for use in different applications, and sometime they are modal and sometimes navigation controllers. For example, go to the code for TwoViewController. Add the following action:

 @IBAction func backButton(_ sender:UIButton){
        guard navigationController?.popViewController(animated: true) != nil else { //modal
            print("Not a navigation Controller")
            dismiss(animated: true, completion: nil)
            return
        }
    }

We expanded the guard clause slightly here from the previous example. If there is no navigation controller, we must be in a modal. Instead of popping the controller, we dismiss it.

Add a Back button to the Two View Controller:

2016-07-08_06-58-13

With the assistant editor open, Control-drag from the Back button we created to the backButton code.

Add another button to View Controller One titled Two Modal.

2016-07-08_07-00-43

Open the assistant editor. Control drag the Two Modal Button to make a new action  named modalTwoButton. Add the following code to the new action to present a modal view:

@IBAction func modalTwoButton(_ sender: UIButton) {
    let vc = TwoViewController(
        nibName: "TwoViewController",
        bundle: nil)
    present(vc,
        animated: true,
        completion: nil)
    }

Build and run. Tap the TwoModal Button, and the modal view slides up from the bottom.

2016-07-08_07-23-36

Tap the Back button and it goes back to View Controller one. Tap the Next button  and you slide sideways into a navigation view.

2016-07-08_07-24-36

Tap Back and you are back in View Controller One

2016-07-08_07-27-12

Using Storyboard ID’s With Navigation Controllers

In between Xibs and the Storyboard are storyboard ID’s.  When you want all of your view controllers on one storyboard, but also want to call the view controller from several different controllers you might want to use a storyboard ID. Storyboard ID’s can programmatically called both by modals and navigation controllers. Some view controllers might have a segue at one place and called by a Storyboard ID in another.  On the storyboard find View Controller Six

2016-07-08_07-32-27

In the Identity inspector, set the Storyboard ID to Six

2016-07-08_07-34-45

On View Controller One add two more Buttons labeled Six Navigation and Six Modal.

2016-07-08_07-38-37

Control-Drag the Six Navigation Button into the assistant editor set to Automatic.  Make an action sixNavigationButton. Now do the same with the modal button. Control-Drag the Six Modal Button into the assistant editor.  Make an action sixModalButton.

The two actions are very similar. They will get a view controller from the method

 storyboard?.instantiateViewController(withIdentifier:String)

then present it for a modal or push it for a navigation controller. Add this code to the two actions:

@IBAction func sixNavigationButton(_ sender: UIButton) {
        guard let vc = storyboard?.instantiateViewController(withIdentifier: "Six") else {
            print("View controller Six not found")
            return
        }
        navigationController?.pushViewController(vc, animated: true)
    }
    
    @IBAction func sixModalButton(_ sender: UIButton) {
        guard let vc = storyboard?.instantiateViewController(withIdentifier: "Six") else {
            print("View controller Six not found")
            return
        }
        present(vc, animated: true, completion: nil)
    }

Go over to the SixViewController class. Add the dismiss method to dismiss the modal in the backButton action :

    @IBAction func backButton(_ sender: UIButton) {
        guard (navigationController?.popViewController(animated:true)) != nil
            else {
                dismiss(animated: true, completion: nil)
                return
        }
    }

Build and run. Tap Six Navigation, and you get to the navigation

2016-07-10_13-35-01

Tap back and you get back to One again. Tap six modal and you get the modal

2016-07-10_13-35-24

Tap back and you get back to One again.

2016-07-10_13-35-40

You’ll notice I left the Root button doing nothing for a modal since it has no meaning for modal.

One More Place to Explore: The Navigation Back Button.

For most cases we get a Back button like this on the navigation bar:

2016-07-08_08-08-37

But you may notice that the Six controller does this, depending where it is pushed from:

2016-07-08_08-07-53

2016-07-08_08-08-16

2016-07-08_08-11-38

The title for the Back button comes from the view controller below it on the stack. When I push Six from Five, Five shows up as the title in the back button. This is another exploration you might want to take about navigation controllers, which you can find in the post Using the Navigation Bar Title and Back Button

The Whole Code

<h2>ViewController.swift</h2>
//
//  ViewController.swift
//  SwiftProgNavControllerDemo
//
//  Created by Steven Lipton on 7/6/16.
//  Copyright © 2016 Steven Lipton. All rights reserved.
//

import UIKit

class ViewController: UIViewController {
//    
// Action for using a story board id for navigation controller
//  let vc = storyboard?.instantiateViewController(withIdentifier: "Six")
//
    @IBAction func sixNavigationButton(_ sender: UIButton) {
        guard let vc = storyboard?.instantiateViewController(withIdentifier: "Six") else {
            print("View controller Six not found")
            return
        }
        navigationController?.pushViewController(vc, animated: true)
    }
    
//    
// Action for using a story board id for modal controller
//  let vc = storyboard?.instantiateViewController(withIdentifier: "Six")
//
    @IBAction func sixModalButton(_ sender: UIButton) {
        guard let vc = storyboard?.instantiateViewController(withIdentifier: "Six") else {
            print("View controller Six not found")
            return
        }
        present(vc, animated: true, completion: nil)
    }
    
//
// modal example for use with dismissal see TwoViewController
//
    @IBAction func modalTwoButton(_ sender: UIButton) {
        let vc = TwoViewController(
            nibName: "TwoViewController",
            bundle: nil)
        present(vc, animated: true, completion: nil)
    }

//
// Example of pushing a view controller 
//navigationController?.pushViewController(vc, animated: true)
//
    @IBAction func nextButton(_ sender: UIButton) {
        let vc = TwoViewController(
            nibName: "TwoViewController",
            bundle: nil)
        navigationController?.pushViewController(vc, animated: true)
    }

//
// Example of Logically pushing a view controller from a segue
// performSegue(withIdentifier: "Four",sender: self)
//
//
    
    @IBAction func fourFiveToggleButton(_ sender: UIButton){
        let normal = UIControlState(rawValue: 0) //beta 1 has no .normal bug#26856201
        if sender.titleLabel?.text == "Four"{
            performSegue(withIdentifier: "Four",
                         sender: self)
            sender.setTitle("Five", for: normal)
        } else{
            performSegue(withIdentifier: "Five",
                         sender: self)
            sender.setTitle("Four", for: normal)
        }
    }

}




<h2>TwoViewController.swift</h2>




//
//  TwoViewController.swift
//  SwiftProgNavControllerDemo
//
//  Created by Steven Lipton on 7/6/16.
//  Copyright © 2016 Steven Lipton. All rights reserved.
//

import UIKit

class TwoViewController: UIViewController {

//
// A back button for dismissal of both modals and navigation controllers
//
//
    @IBAction func backButton(_ sender:UIButton){
        guard navigationController?.popViewController(animated: true) != nil else { //modal
            print("Not a navigation Controller")
            dismiss(animated: true, completion: nil)
            return
        }
    }
}




<h2>ThreeViewController.swift</h2>




//
//  ThreeViewController.swift
//  SwiftProgNavControllerDemo
//
//  Created by Steven Lipton on 7/6/16.
//  Copyright © 2016 Steven Lipton. All rights reserved.
//

import UIKit

class ThreeViewController: UIViewController {
    }





<h2>SixViewController.swift</h2>




//
//  SixViewController.swift
//  SwiftProgNavControllerDemo
//
//  Created by Steven Lipton on 7/8/16.
//  Copyright © 2016 Steven Lipton. All rights reserved.
//

import UIKit

class SixViewController: UIViewController {
 
//
// Another back button for dismissal of both modals and navigation controllers
//
//   
    @IBAction func backButton(_ sender: UIButton) {
        guard (navigationController?.popViewController(animated:true)) != nil
            else {
                dismiss(animated: true, completion: nil)
                return
        }
    }

//
// A pop to root of the navigation controller example 
//  navigationController?.popToRootViewController(animated: true)
//
    @IBAction func rootButton(_ sender: UIButton) {
        guard navigationController?.popToRootViewController(animated: true) != nil
        else {
            print("No Navigation Controller")
            return
        }
    }
    
    }