# 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
}
//volume of a round pizza
func roundVolume(height:Double, radius:Double ) -> Double{
}
```

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
}
```

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

Click Add 2 constraints.  Select the Label. Title it Results.  Click the pin icon  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.

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.
message: "Volume is \(volume)",
```

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:

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

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

```alert.addAction(clearAction)
```

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`.

```
{()->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:

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

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
}
//volume of a round pizza
func roundVolume(height:Double, radius:Double ) -> Double{
}
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
}
//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
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) {
}

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

}

```

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.
//

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.
message: "Volume is \(volume)",

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

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

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

}

}

}
```

# How to Read CSV files from the Web in Swift

There’s a lot of data out there for the taking, if you only know how to get it.  There is a treasure trove of  government-based data sets available to the public. There’s a lot of information free for the taking you might want to know, or add to your app.

There’s also many different ways to get that data. Three data formats CSV, XML,and JSON all provide great ways to getting that data. Some data portals are one type, others you have the option of all of them.  In our last lesson, we began to look at the CSV file format with a data file in the app bundle. In this lesson we’ll dig deeper into CSV files, and learn to load them from an external source.

## The CSV Data Format

We don’t often have just text in a text file. Instead, we use a variety of arrangements to store other types of data than text. One of the oldest of these arrangements is the CSV, or comma separated value file. Here’s an example.

```Title,data1,data2
Hello Pizza!,24,42
Ice Cream,16,32
```

As the name implies, we separated out three values per line by a comma. The CSV file represents this table:

Title data1 data2
Hello Pizza! 24 42
Ice Cream 16 32

While standards exist, you’ll rarely find anyone following them.  There is no real standard for CSV that everyone follows. You’ll find several variations. Fortunately there are a few rules that tend to be true. A row of data usually ends with a newline character `\n`. The elements, which I’ll often call fields of the row have some character to delimit them. The most popular is the comma, but tab characters and the pipe character | show up too. Once again, it’s important to know what you are dealing with. Notice the first line of our CSV file has a description, often referred to as the header, of the column of data. That is helpful, and you’ll find it often in data sets, but it isn’t always there. When writing my own, I tend to include it. Sometimes it is the only documentation about this file.

Now consider this file:

```Title,data1,data2
Hello, Pizza!,24,42
Ice Cream,16,32
```

Line 2 of this file has a problem. The text Hello, Pizza!uses a comma. In CSV,  this means we have four fields in our first row of data, and that messes up our table.

Title data1 data2
Hello Pizza! 24 42
Ice Cream 16 32

There are two approaches in CSV to handle this. One is to change the delimiter from a comma to something not often used as a character. Two common ones are the tab character (Often referred to a Tab-Demlimited) or a pipe `|` character.

```Title|data1|data2
Hello, Pizza!|24|42
Ice Cream|16|32
```

The most common way to handle the problem is to use quotes. Quotes in a CSV file mean this is a string and to include everything in between the quotes as a single field.

```"Title","data1","data2"
"Hello, Pizza!",24,42
"Ice Cream",16,32
```

Some implementations of code are smart enough to know quotes are strings, numbers without decimal points are `Int`, and with decimal points are `Double`. For reasons I’ll discuss later, I usually don’t make things this smart.

Many web data portals such as the Socrata.com platforms listed in the Open Data Network get paranoid about the whole thing and put everything in quotes.

```"Title","data1","data2"
"Hello, Pizza!","24","42"
"Ice Cream","16","32"
```

We’ll be working with files of this last kind. However, any one of these are possible. One of may many rules about using data is always check the specs and context of your data set. Look at that data and code appropriately. Which leads to a disclaimer here. This demo will lead to one way of handling data. There are as many ways of handling data in CSV as there are datasets. For any project, you’ll have to do some work in getting it to work with your data set.

This by the way is why I’m not a big fan of 3rd party libraries. I simply don’t trust them. A lot of talented people did a lot of good work, but I can’t tell that without so much testing and reading of code that I’d write my own a lot faster and keep it up to date a lot easier and faster.

## Biking to the Center of the Universe

The Fremont neighborhood of Seattle has proclaimed itself the Center of the Known Universe. This quirky neighborhood has its own troll, a rocket, and has a statue of Vladimir Lenin.  Adobe and Google both have offices here.  Fremont also has one of the few bridges between the northwest neighborhoods of Seattle and downtown. In October 2012,  Seattle installed bike sensors on the sidewalks of the bridge to count the number of bicycles that cross the bridge.  That data is a rather simple data set where we can see patterns on bicycle traffic over this bridge. In another post, I explained how to download data to a file, which you could then put into the app bundle. That  does not give us updated information. To get updated  information,  we poll the website directly, which is what we’ll do in this lesson.

# Setting up the Storyboard

For this project we’ll use a very simple storyboard. I could do this in the playgrounds, but I find them very slow in compiling.  We’ll display to a text view. Open a new project in Xcode called CSVWebDemo. Set the language to Swift and a Universal device. Save the file and go to the storyboard.   Change the background color of the view to Light gray in the attributes inspector. Find the Text View  in the object library

Drag the text view to the center of the storyboard.

On the auto layout toolbar in the lower right of the  storyboard, click the pin button .  Pin the view 10 Points up, 0 points right, 0 points left, and 20 points down. Be sure to press Tab after each field to make sure the entry takes. Set the Update Frames to Items of New Constraints.

Click the Add 4 Constraints button. We get this:

Open the assistant editor. Control drag from the text view to the `ViewController` class code and make an outlet named textView.

Close the assistant editor.

# The CSVDemo Class

We’ll make a new class for our data model.  Press Command-N and make a new Cocoa Touch class CSVDemo subclassing `NSObject`. Add three properties to the class

```var data:[[String:String]] = []
var columnTitles:[String] = []
var columnType:[String] = ["NSDate","Int","Int"]
```

This class will read the CSV as a text file and store it in a string. We’ll convert it to array containing a data dictionary stored as strings. To help us access that data easily, we have two additional arrays. `columnTitles` is the header from the first row of the array. These are the keys for the dictionaries in `data`. When we need to convert this to the actual data types for the columns, we have a second array for the type of the corresponding column. Looking at the data portal we are getting this data from, we determine those types.

If there’s  API documentation, it will tell us the type:

However, you still might need to do some thinking. From this, I know my first field is an `NSDate.` Since `number` is a count of bikes, `Int` is the best choice for a type for the other two fields.

Our first task is reading a text file as a string into the app. Add this code:

```func readStringFromURL(stringURL:String)-> String!{
if let url = NSURL(string: stringURL) {
do {
return try String(contentsOfURL: url, usedEncoding: nil)
} catch {
return nil
}
} else {
print("String was not a URL")
return nil
}
}
```

We return an optional `String` value from this method. This code could be two lines:

```let url = NSURL(string: stringURL)
return String(contentsOfURL: url, usedEncoding: nil)
```

The first line makes a `NSURL` from the string we pass to it. The second line reads a text file and stores it in a string,  returned in the function.  It would be noce if this was all we needed, but it isn’t. Don’t trust anything when reading and writing data. Neither does iOS, and the `String` initializer that reads data from an external source throws errors. We can have dozens of things go wrong between server, transmission, and client when reading data from the web. Swift forces us to use the `do-catch` clause with this `String` initializer. If the function throws an error, we return `nil` and send a message to the console. We also check that our URL is well formed, THe `NSURL` initilizaer first checks that the string we give it is really a URL If it isn’t, the method returns `nil`.  If it is properly formed, we enter the `do-catch` clause to read the data with the `String:contentsOfURL:usedEncoding `initializer.

Go to `viewDidLoad` in the `ViewController` class. Change `viewDidLoad` to this. To make sure the URL is correct, I suggest copying and pasting this code.

```override func viewDidLoad() {
let csvDemo = CSVDemo()
let stringURL = "https://data.seattle.gov/resource/4xy5-26gy.csv?\$where=date%20between%20%272016-04-01T00:00:00%27%20and%20%272016-04-30T23:00:00%27&\$order=date"
}
```

We make an instance of our model and set a constant to the url we want. While I’ll go into the full anatomy of this URL in a separate lesson, there are a two important points to note. I could have written this

`let stringURL = "https://data.seattle.gov/resource/4xy5-26gy.csv`

which would have given me the full database of 31,000 records unsorted. That is a huge memory investment. Try to load a little as possible and try to avoid heavy processing on the device. Instead leave that heavy lifting to the server, which is what the rest of this URL is about. The API for the Socrata platform allows a subset of SQL call SoQL for retrieving data, so the filtered data is April 2016 and sorted it by date.

We used a `https` in this url. Pay attention if this is a `http` or `https`. iOS doesn’t trust `http`. Since it is a less secure protocol, iOS  and Foundation will reject your request if you use a site that loads from http. I discuss this in more details in my post about web views and security if you want to know how to bypass the iOS security.

Build and run. You’ll get this

I happen to like this view this in landscape. If you want to do that press Command-Right Arrow.

You can scroll down by swiping up. Scroll to  see the last row of the data

# Converting the Data to CSV

The data we have is one long string.  We’d like it to be accessible data. There are many data structures use can use to do that. You can make a struct or class for the data in each row. For this file I could do this.

```class DataRow:NSObject{
var date:NSDate
var northCount:count
var southCount:count
}
```

Then keep the rows together in an array.

```var dataTable = [DataRow]
```

If the data will be used in user interfaces, you want to use an array to arrange the rows. Most of the views that have large sets of data like `UITableView` use arrays.

In our case we’ll use dictionaries. I prefer dictionaries since it’s easy to do repetitive tasks with them. In a class or struct I’d have to directly assign everything. In a dictionary, as long as I have an array of keys, I can make a loop to do that work for me. You could, of course, use an array instead of a dictionary, but Apple uses Dictionaries in some of the other data format conversions so it’s good to get used to it.

As I discussed in the last lesson, there are several steps to converting the string to a CSV data file.

1. Clean the row delimiter to be `\n`
2. Break the string into an array of rows
3. Loop through the array of rows
1. Break the row into an array
2. Place that array into a structure with an element in a new array.
4. Return the new array

We’ll do the same here, with two changes: Our data has quotes around all the fields. We need to remove the quotes. We want our fields to be of type `NSDate` and `Int` instead of strings. We’ll add to 3.1 and 3.2 some code to accomplish these tasks.

## Clean the Row Delimiter

First task is to clean the rows and return the separated rows. Add the following method to `CSVDemo`.

```func cleanRows(stringData:String)->[String]{
var cleanFile = stringData
cleanFile = cleanFile.stringByReplacingOccurrencesOfString("\r", withString: "\n")
cleanFile = cleanFile.stringByReplacingOccurrencesOfString("\n\n", withString: "\n")
return cleanFile.componentsSeparatedByString("\n")
}
```

Or row delimiter is `\n`. We might have some people or systems  who put` \r\n`, `\r`, or `\n\n` instead. To make sure we have the correct delimiter, we replace the string using the `String` function `stringByReplacingOccurrencesOfString:withString:` so they are all `\n`

Once they are `\n`, separate into an array of rows using the `componentsSeparatedByString` string function and return the result

## Clean the Rows of Quotes

Next we’ll clean individual rows and make a string array of them. This works the same way as the previous method. Add this method:

``` func getQuoteFieldsForRow(oldString:String) -> [String]{
let delimiter = "\t"
var newString = oldString.stringByReplacingOccurrencesOfString("\",\"", withString: delimiter)
newString = newString.stringByReplacingOccurrencesOfString(",\"", withString: delimiter)
newString = newString.stringByReplacingOccurrencesOfString("\",", withString: delimiter)
newString = newString.stringByReplacingOccurrencesOfString("\"", withString: "")
return newString.componentsSeparatedByString(delimiter)
}
```

Remember there’s a reason for the quotes. We want to properly reflect commas in the data. So we take the strategy we mentioned earlier of converting quotes to a delimiter we can’t use in the string. I use tabs that delimiter. I find every combination of quotes and change them to  tabs or delete them.

If you are paying attention, you’ll might be wondering something. I said earlier that you should pay attention to the context of your data. Here I have no string types in my data and the comma is not going to show up. I could cut three lines of code from this and just delete the quotes. However, I’m also not sure that data won’t change and integers start using commas. We play it safe by setting things up this way.

# Putting It All Together

We can make nested loops to build our data structure. Add this method to `CSVDemo`

```func convertCSV(stringData:String) -> [[String:AnyObject]] {

let rows = cleanRows(stringData)
if rows.count > 0 {
data = []
columnTitles = cleanFields(rows.first!)
for row in rows{
let fields = cleanFields(row)
}
} else {
print("No data in file")
}
return data
}

```

This is the basic structure of the rows loop. As long as there is one row in the file for each row, we break the row into an array of fields. If there isn’t any rows, we send an error message. We also do something special with the first row, adding its contents into `columnTitles`, the dictionary keys for the other rows.
After the `cleanFields` statement add this:

```if fields.count != columnTitles.count {continue}
```

This is a check that we have a valid row. The header had the names of each row. The number of elements in the fields array should match the number in the `columnTitles` array.  If our current row has a different number of fields, it’s an invalid row. For an invalid row in this demo, I ignore the row by continuing the loop to the next iteration. We can get much fancier though, and warn the app or the user that there is an invalid row or even attempt to fix the row.

Under that, add the next loop

```var newRow = [String:AnyObject]()
for index in 0..<fields.count{
let column = columnTitles[index]
let field = fields[index]
}
data += [newRow]
```

This loops through the fields. This time we have multiple arrays with the same index. The loop therefore uses an integer `index`. We also have a dictionary `newRow` where we’ll store the fields for this row. After the loop of the fields completes, `newRow` is added as a new entry to the array `data`.

I could add just one more line and this would work:

` newRow[column]= field`

Since the value of `newRow` is an `AnyObject`, the strings would store. In the last lesson we did that, storing everything in a string. I could change the string to a more useful type later in a separate function.

However for memory management reasons, it is better to convert to appropriate types now. The number 314159 is six bytes as a `String` and one as an `Int`. We get huge memory and speed savings in bigger files by converting. Therefore we’ll add a parser that converts and saves the data in the type we want.

With CSV, there’s several approaches to this. If you wanted to do this automatically, you could try telling the difference between a String, an Int, and a Double. Strings will have the quotes around them, Assuming we didn’t strip the quotes earlier.  Doubles will have a decimal point. However that’s lot of exceptions and problems. Take the number 1,234,567. If the data contains that number, and your field delimiter is a comma,  it breaks into three integers. Suppose you have these two rows

```"pizza",12,15
"pasta",12.2,56
```

You have in one field the numbers 12 and 12.2. The field should be `Double` but the system might read one as an Int and one as a Double, something any Swift developer who uses implicit typing can appreciate. As I’ll show shortly, dates cannot be converted automatically. For me, it’s too much of a headache. Unless the souce of this data publishes an API for it(and even then I’m suspicious) I skip all this and use explicit typing on my dictionary with `columnType`.

Add this to your code under `let field = fields[index]`.

```switch columnType[index]{
case "Int":
newRow[column] = Int(field)
case "NSDate":
guard let newField = dateFormatter.dateFromString(field) else {
print ("\(field) didn\'t convert")
continue
}
newRow[column] = newField
default: //default remains a string
let newField = field
newRow[column] = newField
}
```

We use a `switch` on `columnType`. Remember, `columnType` has the following values:

`var columnType:[String] = ["NSDate","Int","Int"]`

`columnType` sets up cases for the types we want, an `Int` and `NSDate`. We can add more types here to our hearts desire. We default to a `String` if the field is not a type we listed here.

Converting to `Int` is simple. Cast the field to `Int` then store it in the `newRow` dictionary with the key `column`.

`newRow[column] = Int(field)`

The date is a bit more complicated, and a good example why I used this approach to typing. We use the `NSDateFormatter` method `dateFromString`. This will require us to set a specific date format. Dates have too many formats, and while standards exist, there are almost as many exceptions as standards. Is any given date represented by date `MM-dd-yyyy`, `MM/dd/yy` or `yyyy-MM-dd`? Is the time 12-hour with AM/PM or 24 hour? How many decimal points on the seconds? What in the strong seperates the time from the date? The answers get complex if you have code figuring it out. For converting an external file to an NSDate using NSDateformatter, we have to get explicit with our date format. At the top of the `CSVDemo` class add this property:

```var dateFormat = "yyyy-MM-dd'T'HH:mm:ss.sss"
```

You can find a full table of possible values for the formatting string in the Unicode Technical Standard #35. In our first iteration, the simulator printed the date as `2016-04-01T00:00:00.000`. Set it the same using `yyyy-MM-dd'T'HH:mm:ss.sss`. If anything doesn’t match this time pattern, such as skipping the three decimal point places, `NSDateFormatter` will not convert it.

Just after declaring the function `convertCSV`, add this code to initialize and set the properties of the `NSDateFormatter`.

```let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = dateFormat
dateFormatter.timeZone = NSTimeZone(abbreviation: "GMT")
```

We need to make one important but not obvious setting here: we set the time zone to `GMT` so we have no correction for time zone in our data structure. Otherwise, iOS will input this as GMT time, and then convert it to your local time zone.

Our completed method looks like this:

``` func convertCSV(stringData:String) -> [[String:AnyObject]] {
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = importDateFormat
dateFormatter.timeZone = NSTimeZone(abbreviation: "GMT")
let rows = cleanRows(stringData)
if rows.count > 0 {
data = []
columnTitles = cleanFields(rows.first!)
for row in rows{
let fields = cleanFields(row)
if fields.count != columnTitles.count {continue}
var newRow = [String:AnyObject]()
for index in 0..<fields.count{
let column = columnTitles[index]
let field = fields[index]
switch columnType[index]{
case "Int":
newRow[column] = Int(field)
case "NSDate":
guard let newField = dateFormatter.dateFromString(field) else {
print ("\(field) didn\'t convert")
continue
}
newRow[column] = newField
default: //default keeps as string
newRow[column] = field
}
}
data += [newRow]
}
} else {
print("No data in file")
}
return data
}
```

# Making Some Useful Output

We’ve converted the data into a useful data structure. Now we can use that structure for some computations. Let’s look at the frequencies and averages of crossing the bridge. Add this code:

```    func printTotalsAndRatio()-> String{
var north = 0
var south = 0
for index in 1..<data.count{
let row = data[index]
north += row["fremont_bridge_nb"] as! Int
south += row["fremont_bridge_sb"] as! Int
}
let totalCrossings = north + south
let totalAverageCrossings = totalCrossings / 30
let averageNorthCrossings = north / 30
let averageSouthCrossings = south / 30
let crossingRatio = Double(north) / Double(south)
var displayString = "Fremont Bridge April 2016 Data\n"
displayString += String(format:"North Side Count:%8i  SouthSide Count%8i\n",north,south)
displayString += String(format:"Total Crossings:%8i\n",totalCrossings)
displayString += String(format:"Average Crossings per day:%8i\n",totalAverageCrossings)
displayString += String(format:"North Side Average:%8i  SouthSide Average%8i\n", averageNorthCrossings,averageSouthCrossings)
displayString += String(format:"North/South ratio:%8.3f",crossingRatio)
return displayString
}
```

The first part of the method totals the number of northbound and southbound crossings of the bridge. The second part uses those totals to compute a few monthly statistics. The third creates a string presenting that information.

Go to the `ViewController` class. Change `viewDidLoad` to this:

```override func viewDidLoad() {
let csvDemo = CSVDemo()
let stringURL = "https://data.seattle.gov/resource/4xy5-26gy.csv?\$where=date%20between%20%272016-04-01T00:00:00%27%20and%20%272016-04-30T23:00:00%27&\$order=date"
csvDemo.convertCSV(textView.text)
textView.text = csvDemo.printTotalsAndRatio()
}
```

Build and run. We get some results.

This is a bridge used primarily by commuters to downtown Seattle. It’s therefore not surprising that there is close to an even distribution of people going both north and south.

# There’s Always One More Bug

You’ll also notice the console had this:
`date didn't convert`
We need to make a small change to our code. Find this line in the `convertCSV` method:

`for index in 0..<fields.count{`

This reads the title row along with everything else. We don’t want to read the header row when converting data. change the code to this:

`for index in 0..<fields.count{`

With this simple change, the header is excluded data, and not converted to dates and integers.

# What CSV Lacks

CSV is very popular with those transferring data into or out of spreadsheets. Most spreadsheets use only a few data types and is thus easy to use. However, it fails miserably once you get to more complex data types. Some have tried an array (see the Violations column in this data base for example) but the results are rather painful to work with. Dictionary types are near impossible in CSV. What if you want to need those types in your dataset? For dealing with such complex issues our next few lessons on XML and JSON will give us solutions.

# The Whole Code

## ViewController.swift

```//
//  ViewController.swift
//  CSVWebDemo
//
//  Created by Steven Lipton on 5/27/16.
//

import UIKit

class ViewController: UIViewController {

@IBOutlet weak var textView: UITextView!
let csvDemo = CSVDemo()
let stringURL = "https://data.seattle.gov/resource/4xy5-26gy.csv?\$where=date%20between%20%272016-04-01T00:00:00%27%20and%20%272016-04-30T23:00:00%27&\$order=date"
csvDemo.convertCSV(textView.text)
textView.text = csvDemo.printTotalsAndRatio()
}
}
```

## CSVDemo.swift

```//
//  CSVDemo.swift
//  CSVWebDemo
//
//  Created by Steven Lipton on 5/27/16.
//

import UIKit

class CSVDemo: NSObject {
var  data:[[String:AnyObject]] = []
var  columnTitles:[String] = []
var  columnType:[String] = ["NSDate","Int","Int"]
var  importDateFormat = "yyyy-MM-dd'T'HH:mm:ss.SSS"

func cleanRows(stringData:String)->[String]{
//use a uniform \n for end of lines.
var cleanFile = stringData
cleanFile = cleanFile.stringByReplacingOccurrencesOfString("\r", withString: "\n")
cleanFile = cleanFile.stringByReplacingOccurrencesOfString("\n\n", withString: "\n")
return cleanFile.componentsSeparatedByString("\n")
}

func cleanFields(oldString:String) -> [String]{
let delimiter = "\t"
var newString = oldString.stringByReplacingOccurrencesOfString("\",\"", withString: delimiter)
newString = newString.stringByReplacingOccurrencesOfString(",\"", withString: delimiter)
newString = newString.stringByReplacingOccurrencesOfString("\",", withString: delimiter)
newString = newString.stringByReplacingOccurrencesOfString("\"", withString: "")
return newString.componentsSeparatedByString(delimiter)
}

func convertCSV(stringData:String) -> [[String:AnyObject]] {
//for date formatting
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = importDateFormat
//dateFormatter.timeZone = NSTimeZone(abbreviation: "GMT")

let rows = cleanRows(stringData)
if rows.count > 0 {
data = []
columnTitles = cleanFields(rows.first!)
for row in rows{
let fields = cleanFields(row)
if fields.count != columnTitles.count {continue}
var newRow = [String:AnyObject]()
for index in 1..<fields.count{ let column = columnTitles[index] let field = fields[index] switch columnType[index]{ case "Int": newRow[column] = Int(field) case "NSDate": guard let newField = dateFormatter.dateFromString(field) else { print ("\(field) didn\'t convert") continue } newRow[column] = newField default: //default keeps as string newRow[column] = field } } data += [newRow] } } else { print("No data in file") } return data } func printTotalsAndRatio()-> String{
var north = 0
var south = 0
for index in 1..<data.count{ let row = data[index] north += row["fremont_bridge_nb"] as! Int south += row["fremont_bridge_sb"] as! Int } let totalCrossings = north + south let totalAverageCrossings = totalCrossings / 30 let averageNorthCrossings = north / 30 let averageSouthCrossings = south / 30 let crossingRatio = Double(north) / Double(south) var displayString = "Fremont Bridge April 2016 Data\n" displayString += String(format:"North Side Count:%8i SouthSide Count%8i\n",north,south) displayString += String(format:"Total Crossings:%8i\n",totalCrossings) displayString += String(format:"Average Crossings per day:%8i\n",totalAverageCrossings) displayString += String(format:"North Side Average:%8i SouthSide Average%8i\n", averageNorthCrossings,averageSouthCrossings) displayString += String(format:"North/South ratio:%8.3f",crossingRatio) return displayString } func readStringFromURL(stringURL:String)-> String!{
if let url = NSURL(string: stringURL) {
do {
return try String(contentsOfURL: url, usedEncoding: nil)

} catch {
return nil
}
} else {
print("String was not a URL")
return nil
}
}

}

```

# Adding Annotations and Overlays to Maps

In the last lesson, we explored the  joys of making maps using the `UIMapView` and `MapKit`. While showing maps is great, we often want to add things to a map, such as locations and graphics.  These are known as Annotations and Overlays. In this lesson we’ll make some of each. We’ll start by locating pizza restaurants in Chicago, then adding a 2 kilometer pizza delivery region for a pizza chain using overlays. Finally we’ll map out how to get from the former Marshall Field’s (now Macy’s) to the first Deep Dish pizza.

# Make a New Project

I’ll quickly go through the the basic setup of a map. For more detail see the previous lesson. Start by making a New Single-view  project Called MapAnnotationsOverlayDemo. Use a Universal device and Swift as the language.   When it loads, we need to turn on `MapKit`.  In the Project Properties, click on the the Capabilities tab. You will see a list of functions we can use. About halfway down the list you’ll See Maps

Turn on maps and the menu opens.

We won’t be changing anything here, but the framework will load when we need it.

Go to the storyboard.  In the Object Library, find the  Map  Kit View object

Drag it somewhere on the story board.

Select the Map view. Click the   button in the Auto Layout  menu on the lower right of the storyboard. This will bring up the the pin menu. Click off Constrain to margins. Set the margins to be 0 on all sides. Change the Update Frames to Items of New Constraints.  Your pin menu should look like this.

Click Add 4 Constraints. The map view takes the entire view on the story board.

With the map view still selected, look at the attribute inspector.  At the top is some attributes specific to map views:

Turn off Points of Interest. They will get in the way of our app.

Open the Assistant editor.  Go to the ViewController.swift file.  Before we do anything else, we needto import  `MapKit. `It is a separate framework than `UIKit`.  Add `import` `MapKit`

```import UIKit
import MapKit
```

Control-drag from the map view on the storyboard to the code. Add the outlet mapView.  We also need to add the delegate `MKMapViewDelegate`. Just to keep things organized, I added a few marks. When done your  `ViewController` code should look like this:

```//MARK: Global Declarations
class ViewController: UIViewController,MKMapViewDelegate {
//MARK: Properties and Outlets
@IBOutlet weak var mapView: MKMapView!
//MARK: - Annotations
//MARK: - Overlays
//MARK: - Map setup
//MARK: Life Cycle
}
}
```

There’s a coordinate we’ll use as a reference point for the city of Chicago. The city, and some of the suburbs use the same grid system for addresses. There is an origin point for this grid in downtown Chicago, where we can say we are at 0,0. That is the intersection of State and Washington Streets. We’ll use it in a few places, thus I’ll use a global constant. Add this code above the class definition for `ViewController`  just below the` Global Declarations` mark:

```//MARK: Global Declarations
let chicagoCoordinate = CLLocationCoordinate2DMake(41.8832301, -87.6278121)// 0,0 Chicago street coordinates
```

Add the following method to `ViewController` to set the initial region for our app with 5 kilometers (3 miles) boundaries:

```//MARK: - Map setup
func resetRegion(){
let region = MKCoordinateRegionMakeWithDistance(chicagoCoordinate, 5000, 5000)
mapView.setRegion(region, animated: true)
}
```

Add the region to `viewDidLoad`:

```override func viewDidLoad() {
resetRegion()
}
```

Build and run. You get a map of downtown Chicago.

# Adding a Single Annotation Pin

The most common and simplest annotation is a pin. There is a special class of annotations `MKPinAnnotationView` for displaying pins. This is a subclass of the more generic `MKAnnotationView`, which uses a  custom class that adopts the `MKAnnotation` Protocol for its data source. Between the `chicagoCoordinate` and the `ViewController` declarations, add this class:

```class ChicagoCenterCoordinate: NSObject,MKAnnotation{
var coordinate: CLLocationCoordinate2D = chicagoCoordinate
var title: String? = "0,0 Street Numbers"
}
```

Any object can be an annotation object. Here we have a  `NSObject` adopting the `MKAnnotation` protocol. Unlike other protocols, `MKAnnotation` does not have required methods, but required properties. You must declare a property `coordinate`. You can optionally declare `title` and `subtitle` as well. If you have other information, you can pass that along too.

The annotation must be added to `mapView`. Change `viewDidLoad` like this:

```override func viewDidLoad() {
resetRegion()
}
```

Build and run. You get a pin at the center coordinates:

Tap the pin and you get a title.

# Using More Than One Pin

If you had only one annotation, this would be an acceptable way of using them. However you will likely have many annotations. Annotations work like table views, they reuse existing annotations to conserve resources. Unlike table views, they can work automatically if you want the default set of features.

## A New Data Set

We’ll need a new data set of several locations. In this demo We’ll use a few deep dish pizza restaurants in Chicago. Press Command-N and make a new Cocoa Touch Class named PizzaLocation.swift, subclassing `NSObject`. Add the following code to the new class:

```import UIKit
import MapKit
class PizzaLocation: NSObject, MKAnnotation{
var identifier = "pizza location"
var title: String?
var coordinate: CLLocationCoordinate2D
init(name:String,lat:CLLocationDegrees,long:CLLocationDegrees){
title = name
coordinate = CLLocationCoordinate2DMake(lat, long)
}
}
```

Once again we `import MapKit` to get the data types we need for locations. In line 3, We add the `MKAnnotation` protocol to the class. This time we have three properties: the required `coordinate`, `title`, and the reuse `identifier` for this annotation. In lines 7 – 10 we have an initializer taking a name, a latitude and longitude to populate the `title` and `coordinate` for each instance of this object.

This is the code for the annotation. Usually, you would have this class read an internal file or get annotation from a server. However, I want to keep this simple and on topic, so I’ll make a constant array for our annotations. Under this class we’ll add one more class. In this class, we’ll have one property: an array of `PizzaLocation`s. Add this(which I seriously suggest cutting and pasting):

```class PizzaLocationList: NSObject {
var restaurant = [PizzaLocation]()
override init(){
restaurant += [PizzaLocation(name:"Connie's Pizza",lat:41.84937922,long:-87.6410584  )]
restaurant += [PizzaLocation(name:"Connie's Pizza",lat:41.90146341,long: -87.62848137 )]
restaurant += [PizzaLocation(name:"Connie's Pizza",lat:41.85110748,long: -87.61286663 )]
restaurant += [PizzaLocation(name:"Connie's Pizza",lat:41.89224916,long:-87.60951805  )]
restaurant += [PizzaLocation(name:"Giordano's",lat:42.00302015,long:-87.81630768  )]
restaurant += [PizzaLocation(name:"Giordano's",lat:41.79915575,long:-87.59028088)]
restaurant += [PizzaLocation(name:"Giordano's",lat:41.85776469,long:-87.66138509)]
restaurant += [PizzaLocation(name:"Giordano's",lat:41.95296188,long:-87.77541371)]
restaurant += [PizzaLocation(name:"Pequod's",lat:41.92185084,long:-87.66451631)]
restaurant += [PizzaLocation(name:"Pizzeria DUE",lat:41.89318499,long:-87.62661003)]
restaurant += [PizzaLocation(name:"Pizzeria UNO",lat:41.8924923,long:-87.626859)]
restaurant += [PizzaLocation(name:"Gino's East",lat:41.8959379,long:-87.6229284)]
restaurant += [PizzaLocation(name:"Lou Malnati's",lat:41.95340615,long:-87.73214376)]
restaurant += [PizzaLocation(name:"Lou Malnati's",lat:41.87169869,long:-87.62737565)]
restaurant += [PizzaLocation(name:"Lou Malnati's",lat:41.96074325,long:-87.6835484)]
restaurant += [PizzaLocation(name:"Lou Malnati's",lat:41.88411358,long:-87.65808167)]
restaurant += [PizzaLocation(name:"Lou Malnati's",lat:41.85186556,long:-87.72202439)]
restaurant += [PizzaLocation(name:"Lou Malnati's",lat:41.90239382,long:-87.62846892)]
restaurant += [PizzaLocation(name:"Lou Malnati's",lat:41.89031406,long:-87.63388913)]
restaurant += [PizzaLocation(name:"Lou Malnati's",lat:41.92911995,long:-87.65359186)]
restaurant += [PizzaLocation(name:"Lou Malnati's",lat:41.9089214,long:-87.6775678)]
}
}
```

I did the work of looking up all those locations. The initializer here populates the array `restuarant`.

## Adding an Array of Annotations to the Map

Go back to `ViewController`. Add a constant `restaurants` to the class

`let restaurants = PizzaLocationList().restaurant`

Change `viewDidLoad` to this:

```override func viewDidLoad() {
resetRegion()
}
```

We added the  `addAnnotation `counterpart `addAnnotations`, which takes an array of `MKAnnotation`s instead of a single annotation.

Build and run. You get a series of pins.

Head south and you’ll find less pins. Click on the one I did and you’ll find it is Connie’s Pizza.

# Using the Map Kit Delegate for Annotations

Annotations default to a red pin with a call out for the title and subtitle. If all you want to do is put a set of red pins on the map, populate the array `annotation` with objects adopting the `MKAnnotation` protocol. You’ll notice however you can’t tell what these pins are without clicking them. To customize the annotations in any way, you’ll need a method in `MKMapViewDelegate`. The delegate method `mapview:viewForAnnotation` works like `tableview:cellForRowAtIndexPath` works for tables. It creates the annotations you need at any given time. Add this to the `ViewController` class

```func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
var view : MKPinAnnotationView
guard let annotation = annotation as? PizzaLocation else {return nil}
if let dequeuedView = mapView.dequeueReusableAnnotationViewWithIdentifier(annotation.identifier) as? MKPinAnnotationView {
view = dequeuedView
}else { //make a new view
view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: annotation.identifier
}
return view
}
```

The function `mapview:viewForAnnotation` has a map view and an annotation for parameters, which we return a optional `MKAnnotoationView`. `nil` means we don’t have a pin here for this annotation for some reason. `MKAnnotationView` is a `UIView` for a more flexible annotation. For convenience `MapKit` has a subclass of `MKAnnotationView` named `MKPinAnnotationView` which sets a pin at a annotation’s location.

We start this function with declaring a view of class `MKPinAnotationView`, since they are the easiest type of annotation view. I’m a bit careful about my annotations, and use `guard` to make sure I get the correct type of annotation, a `PizzaLocation`. Like table cells, annotations dequeue. For that to work properly we need an identifier, which we find in `annotation.identifier`. I check for an existing dequeued view, using that `identifier` property of `PizzaLocation`. If the annotation has already been created I assign it to the view. If it isn’t I can make a new view, assigning the reuse identifier to the annotation view.
As this is a delegate, don’t forget to set the delegate in `viewDidLoad`.

`mapkit.delegate = self`

Build and run. You get the same map as before…almost.

You cannot get the title in a call out if you click on the pin. Once we start making our own `MKAnnotationview`s, we have to specify how we want annotation view to look and behave.

# Changing Pin Color

Starting in iOS9, we can make the pin color any color we wish using the `pinTintColor` property of `MKPinAnnotation`. Before we do, add this function to `ViewController`

```    func pinColor(name:String) -> UIColor{
var color = UIColor.purpleColor()
switch name{
case "Connie's Pizza":
color = UIColor.blueColor()
case "Lou Malnati's":
color = UIColor.greenColor()
case "Giordano's":
color = UIColor.yellowColor()
default:
color = UIColor.orangeColor()
}
return color
}
```

This changes the color of the pin based on the pizza chain. Just before the `return view` in `mapview:viewForAnnotation` add the highlighted line:

```    func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
var view : MKPinAnnotationView
guard let annotation = annotation as? PizzaLocation else {return nil}
if let dequeuedView = mapView.dequeueReusableAnnotationViewWithIdentifier(annotation.identifier) as? MKPinAnnotationView {
view = dequeuedView
}else {
view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: annotation.identifier)
}
view.pinTintColor = pinColor(annotation.title!)
return view
}
```

Once we get the view, we set the pin color. Build and run. Now the pins are colorful.

One thought about style and user interfaces when changing the pin colors. Looking at these pins can you tell which pins are Lou Malnati’s? Without a key on the map it’s difficult. Use color apraingly and for uses that color makes sense. If I was rating these restaurants. using red, green and and yellow tints tell me which ones to go to and which ones to avoid

# Multiple Classes of Annotations

You’ll see one red pin. In our code, we never specified a red pin. Why it it there? Zoom in on the location (option-drag in the simulator) and you’ll find it is the center coordinate of State and Washington streets.

Look back a the delegate methods and find this line of code:

`guard let annotation = annotation as? PizzaLocation else {return nil}`

This code returns `nil` if we cannot downcast to `PizzaLocation`, which we can’t with  class `ChicagoCenterCoordinate`. For any `nil` annotation view, we get our default red pin. We need to change the code to downcast for `ChicagoCenterCoordinate`, then set properties on that pin. Change the code to this:

``` func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
if let annotation = annotation as? PizzaLocation{
if let view = mapView.dequeueReusableAnnotationViewWithIdentifier(annotation.identifier) as? MKPinAnnotationView {
return view
}else{
let view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: annotation.identifier)
view.pinTintColor = pinColor(annotation.title!)
return view
}
}else{
if let annotation = annotation as? ChicagoCenterCoordinate{
if let view = mapView.dequeueReusableAnnotationViewWithIdentifier("center") as? MKPinAnnotationView {
return view
}else {
let view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "center")
view.pinTintColor = UIColor.blackColor()
return view
}
}
}
return nil
}

```

We test for an annotation to cast properly to `ChicagoCenterCoordinate`, and then make a black pin if necessary. Build and run. You now have the black pin.

# Customizing the Annotation

There are several properties in `MKAnnotationView` we can use to customize the annotation view. We can get back the call out with two lines of code. Add this under the `pinTintColor` of black.

```view.pinTintColor = UIColor.blackColor()
view.enabled = true
view.canShowCallout = true
```

Build and Run. Click the black pin and you get a call out.

We can customize the appearance of the pin. The pin is a `UIImage`. We can add an image to the annotation in its `image` property. Here are two images we can use for the annotations we have

Right click each and save the images as pizza pin and crosshairs respectively.
Go to `Assets.xcassets`. From where you saved the images, drag the pizza pin into the assets folder, so it creates a new image.

Check the image set attributes to make sure this image set has the name pizza pin.

Do the same for the cross hairs, making sure the image set name is crosshairs.

Add two news constants to the beginning of the `ViewController` code. This speeds loading the image later in the delegate.

```let pizzaPin = UIImage(named: "pizza pin")
let crossHairs = UIImage(named: "crosshairs")
```

Change the code for `mapView:viewForAnnotation:` to this

```func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
if let annotation = annotation as? PizzaLocation{
if let view = mapView.dequeueReusableAnnotationViewWithIdentifier(annotation.identifier){
return view
}else{
let view = MKAnnotationView(annotation: annotation, reuseIdentifier: annotation.identifier)
view.image = pizzaPin
view.enabled = true
view.canShowCallout = true
view.leftCalloutAccessoryView = UIImageView(image: pizzaPin)
return view
}
}else{
if let annotation = annotation as? ChicagoCenterCoordinate{
if let dequeuedView = mapView.dequeueReusableAnnotationViewWithIdentifier("center"){
return dequeuedView
}else {
let view = MKAnnotationView(annotation: annotation, reuseIdentifier: "center")
view.image = crossHairs
view.enabled = true
view.canShowCallout = true
return view
}
}
}
return nil
}
```

Lines 3,6,14,and 18 uses`MKAnnotationView` instead of `MKPinAnnotationView` in order to use a custom image. A pin will replace your image if you use `MKPinAnnotationView` In line 7, we set the `image` property of the annotation view to our pizza pin. Similiarly line 19 add our crosshairs. Lines 8 and 9 enable the call out with the title. Line 10 adds a view to the callout. This can be any subclass of `UIView`, including controls such as buttons. We make a `UIImageView` from the pizza pin image.

Build and run. You get the pizza image instead of the pin, with cross hairs at State and Washington streets.

Click a Pizza restaurant and you get its name and the pizza icon

# Working with Overlays

In some cases we don’t need a point for an annotation but an area, line or tile. To show those on a map, we use an overlay. Overlays set up a lot like annotations. We start with a overlay object and in the `MapKitDelegate` method for overlays, tell the system what overlay view goes where.

Overlays can have several standard shapes.You can use circles, polygons, and polylines as built in shapes, plus the tile overlay. We’ll look at the polyline and circle for our examples.

## Circle Overlays

Suppose we want to show a delivery area based on a distance from the restaurant. We can display that with a circle for the delivery area. We need an instance of the `MKCircle` class to do that. `MKCircle` has several initializers depending on your measurement system. We’re sticking to coordinates, so we’ll use the coordinate of the restaurant as our center and a distance in meters which becomes the radius of our circle. Add this code:

``` func deliveryOverlay(restaurantName:String, radius:CLLocationDistance){
for restaurant in restaurants{
if restaurant.title == restaurantName{
let center = restaurant.coordinate
}
}
}
```

We do a linear search for the specific restaurant, adding the circle overlay to `mapView` if it is the restaurant we are looking for. We’ll also need the delegate method to make a overlay renderer, just like an annotation needed an annotation view. Add this code to `ViewController`:

```func mapView(mapView: MKMapView, rendererForOverlay overlay: MKOverlay) -> MKOverlayRenderer {
if overlay.isKindOfClass(MKCircle){
let circleRenderer = MKCircleRenderer(overlay: overlay)
circleRenderer.fillColor = UIColor.blueColor().colorWithAlphaComponent(0.1)
circleRenderer.strokeColor = UIColor.blueColor()
circleRenderer.lineWidth = 1
return circleRenderer
}
return MKOverlayRenderer(overlay: overlay)
}
```

This delegate method returns a `MKOverlayRenderer`, from the `MKOverlay` parameter. `MKOverlayRenderer` is a form of UIView, which means most core graphics properties and function work on it. Since we may have more than one subclass of MKOverlay in the delegate, Line 2 checks if we have an `MKCircle` before we make it a `MKCircleRenderer`. Lines 3 through 5 set the color and stroke of the circle. Line 6 returns our circle to the map for rendering. In case this was not a circle, we have a catch all `return` to end the code.

Add the function at 2 Kilometers for Connie’s pizza into `viewDidLoad`. This really isn’t their delivery area, we’re making this up for the example.

```override func viewDidLoad() {
resetRegion()
mapView.delegate = self
}
```

Build and run. You get the circles, but they are a bit big for our view.

Zoom out a little (use the option key to pinch on the simulator) to see the full circles.

## Rendering Polylines in Overlays

Both poly lines and polygons are an array of coordinates making up a line. The difference is the polygon closes the shapes and allows filling while the the polyline doesn’t Polylines are the way we mark routes on a map.

Unlike the last lesson, the only Chicago trivia I’ve given is the address center of Chicago at State and Washington streets. Let’s make a walking path from the center of the addresses to the center of the Deep Dish pizza universe: Pizzeria Uno. There’s plenty of debate wiether it was Owner Ike Sewell or Chef Rudy Malnati who invented deep dish pizza, but it’s clear this was the restaurant that it happened. As you can tell from the pins on our map, Rudy’s son Lou (who was also a manager at UNO’s) started his own chain first in the North and northwest suburbs and then pretty much spread to most of Chicago. I didn’t include all 45 Chicago area Malnati’s locations in this data set. Lou Malnati’s #46 in Phoenix Arizona opens the same day I’m posting this.

One of the great things about Chicago is the grid system. We need to walk in one direction for a while, make a turn and then walk in the new direction. Without using the directions API, we can get there with only three coordinates. We already have two, and I’ll give you the third. Add this function to our code:

```func UnoDirections(){
var coordinates = [CLLocationCoordinate2D]()
coordinates += [ChicagoCenterCoordinate().coordinate] //State and Washington
coordinates += [CLLocationCoordinate2D(latitude: 41.8924847, longitude: -87.6280187)]
coordinates += [restaurants[10].coordinate] //Uno's
let path = MKPolyline(coordinates: &coordinates, count: coordinates.count)
}
```

`MKPolyline` and `MKPolygon` need an array of `CLLocationCoordinate2D`. We make that array by taking our center coordinate, the coordinate of the traffic intersection we make our turn and the restaurant coordinates. We get a `MKPolyLine `object `path` from the coordinates and a count of the number of coordinates. You’ll notice we used` &coordinates` and not `coordinates`. This parameter takes the array as an evil (or at least dangerous) `UnsafeMutablePointer`. We don’t pass values to this, we share them with an `&`. Once we have the path, we add it to the `overlay` array in `mapView`.

Next we make a few additions to the delegate method.

```func mapView(mapView: MKMapView, rendererForOverlay overlay: MKOverlay) -> MKOverlayRenderer {
if overlay.isKindOfClass(MKCircle){
let circleRenderer = MKCircleRenderer(overlay: overlay)
circleRenderer.fillColor = UIColor.blueColor().colorWithAlphaComponent(0.1)
circleRenderer.strokeColor = UIColor.blueColor()
circleRenderer.lineWidth = 1
return circleRenderer
}
if overlay.isKindOfClass(MKPolyline){
let polylineRenderer = MKPolylineRenderer(overlay: overlay)
polylineRenderer.strokeColor = UIColor.blueColor()
polylineRenderer.lineWidth = 2
return polylineRenderer
}
return MKOverlayRenderer(overlay: overlay)
}
```

The `MKpolylineRenderer` works much like the `MKCircleRenderer`. We check if `overlay` is the correct class. If so, we get an instance of the renderer, and set some properties of the line. In this case, we have no fill.
Add `UnoDirections` to `viewDidload`:

`UnoDirections()`

Build and run. You’ll see a line on the map now.

Since Uno’s is only a block east of State Street. We are losing our line under the annotations. Zoom in on the map and you can see it better.

# Where to Go from Here

This is the basics of annotations and overlays. From this you can do a lot, as long as you have good coordinate data. What I’ve covered in this and the last lesson was how to make a user interface with the map. What I didn’t cover here was any of the core location stuff. I didn’t tell you how to find the location of the device, nor did I show you how to get directions. Those are lessons unto themselves.

I’m going to use maps and tables in upcoming lessons to discuss the form for large data sets, such as JSON and XML. You’ll see more about annotations and the like in upcoming lessons as we get data from external sources.

# The Whole Code

## ViewController.swift

```//
//  ViewController.swift
//  MapAnnotationsOverlayDemo
//
//  Created by Steven Lipton on 5/10/16.
//

import UIKit
import MapKit
//MARK: Global Declarations
let chicagoCoordinate = CLLocationCoordinate2DMake(41.8832301, -87.6278121)// 0,0 Chicago street coordinates

class ChicagoCenterCoordinate: NSObject,MKAnnotation{
var coordinate: CLLocationCoordinate2D = chicagoCoordinate
var title: String? = "0,0 Street Numbers"
}

class ViewController: UIViewController,MKMapViewDelegate {
//MARK: Properties and outlets
let pizzaPin = UIImage(named: "pizza pin")
let crossHairs = UIImage(named: "crosshairs")
let restaurants = PizzaLocationList().restaurant
@IBOutlet weak var mapView: MKMapView!

//MARK: - Annotations
/* Since the annotations get loaded in viewDidLoad, this is three iterations of the delegate mapView:viewForAnnotation: */

func pinColor(name:String) -> UIColor{
var color = UIColor.purpleColor()
switch name{
case "Connie's Pizza":
color = UIColor.blueColor()
case "Lou Malnati's":
color = UIColor.greenColor()
case "Giordano's":
color = UIColor.yellowColor()
default:
color = UIColor.orangeColor()
}
return color
}

/* Iteration 1 -- single annotation type */
/*
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
guard let annotation = annotation as? PizzaLocation else {return nil}
if let view = mapView.dequeueReusableAnnotationViewWithIdentifier(annotation.identifier) as? MKPinAnnotationView {
return view
}else {
let view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: annotation.identifier)
view.pinTintColor = pinColor(annotation.title!)
return view
}
}
*/

/* Iteration 2 -- two classes of annotation using MKPinAnnotationView */
/*
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
if let annotation = annotation as? PizzaLocation{
if let view = mapView.dequeueReusableAnnotationViewWithIdentifier(annotation.identifier) as? MKPinAnnotationView {
return view
}else{
let view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: annotation.identifier)
view.pinTintColor = pinColor(annotation.title!)
return view
}
}else{
if let annotation = annotation as? ChicagoCenterCoordinate{
if let view = mapView.dequeueReusableAnnotationViewWithIdentifier("center") as? MKPinAnnotationView {
return view
}else {
let view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "center")
view.pinTintColor = UIColor.blackColor()
return view
}
}
}
return nil
}

*/
/* iteration 3 Using MKAnnotationView and custom images */
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {

if let annotation = annotation as? PizzaLocation{
if let view = mapView.dequeueReusableAnnotationViewWithIdentifier(annotation.identifier){
return view
}else{
let view = MKAnnotationView(annotation: annotation, reuseIdentifier: annotation.identifier)
view.image = pizzaPin
view.enabled = true
view.canShowCallout = true
view.leftCalloutAccessoryView = UIImageView(image: pizzaPin)
return view
}
}else{
if let annotation = annotation as? ChicagoCenterCoordinate{
if let dequeuedView = mapView.dequeueReusableAnnotationViewWithIdentifier("center"){
return dequeuedView
}else {
let view = MKAnnotationView(annotation: annotation, reuseIdentifier: "center")
view.image = crossHairs
view.enabled = true
view.canShowCallout = true
return view
}
}
}
return nil
}
//MARK: - Overlays

for restaurant in restaurants{
if restaurant.title == restaurantName{
let center = restaurant.coordinate
}
}
}

func UnoDirections(){
var coordinates = [CLLocationCoordinate2D]()
coordinates += [ChicagoCenterCoordinate().coordinate] //State and Washington
coordinates += [CLLocationCoordinate2D(latitude: 41.8924847, longitude: -87.6280187)]
coordinates += [restaurants[10].coordinate] //Uno's
let path = MKPolyline(coordinates: &coordinates, count: coordinates.count)
}
//MARK: Overlay delegate

func mapView(mapView: MKMapView, rendererForOverlay overlay: MKOverlay) -> MKOverlayRenderer {
if overlay.isKindOfClass(MKCircle){
let circleRenderer = MKCircleRenderer(overlay: overlay)
circleRenderer.fillColor = UIColor.blueColor().colorWithAlphaComponent(0.1)
circleRenderer.strokeColor = UIColor.blueColor()
circleRenderer.lineWidth = 1
return circleRenderer
}

if overlay.isKindOfClass(MKPolyline){
let polylineRenderer = MKPolylineRenderer(overlay: overlay)
polylineRenderer.strokeColor = UIColor.blueColor()
polylineRenderer.lineWidth = 2
return polylineRenderer
}

return MKOverlayRenderer(overlay: overlay)
}
//MARK: - Map setup
func resetRegion(){
let region = MKCoordinateRegionMakeWithDistance(chicagoCoordinate, 5000, 5000)
mapView.setRegion(region, animated: true)
}

//MARK: Life Cycle
resetRegion()
UnoDirections()
mapView.delegate = self
}

}```

## PizzaLocation.swift

```//
//  PizzaLocation.swift
//  mapAnnotationsDemo
//
//  Created by Steven Lipton on 5/10/16.
//

import UIKit
import MapKit

class PizzaLocation: NSObject, MKAnnotation{
var identifier = "pizza location"
var title: String?
var coordinate: CLLocationCoordinate2D
init(name:String,lat:CLLocationDegrees,long:CLLocationDegrees){
title = name
coordinate = CLLocationCoordinate2DMake(lat, long)
}
}

class PizzaLocationList: NSObject {
var restaurant = [PizzaLocation]()
override init(){
restaurant += [PizzaLocation(name:"Connie's Pizza",lat:41.84937922,long:-87.6410584  )]
restaurant += [PizzaLocation(name:"Connie's Pizza",lat:41.90146341,long: -87.62848137 )]
restaurant += [PizzaLocation(name:"Connie's Pizza",lat:41.85110748,long: -87.61286663 )]
restaurant += [PizzaLocation(name:"Connie's Pizza",lat:41.89224916,long:-87.60951805  )]
restaurant += [PizzaLocation(name:"Giordano's",lat:42.00302015,long:-87.81630768  )]
restaurant += [PizzaLocation(name:"Giordano's",lat:41.79915575,long:-87.59028088)]
restaurant += [PizzaLocation(name:"Giordano's",lat:41.85776469,long:-87.66138509)]
restaurant += [PizzaLocation(name:"Giordano's",lat:41.95296188,long:-87.77541371)]
restaurant += [PizzaLocation(name:"Pequod's",lat:41.92185084,long:-87.66451631)]
restaurant += [PizzaLocation(name:"Pizzeria DUE",lat:41.89318499,long:-87.62661003)]
restaurant += [PizzaLocation(name:"Pizzeria UNO",lat:41.8924923,long:-87.626859)]
restaurant += [PizzaLocation(name:"Gino's East",lat:41.8959379,long:-87.6229284)]
restaurant += [PizzaLocation(name:"Lou Malnati's",lat:41.95340615,long:-87.73214376)]
restaurant += [PizzaLocation(name:"Lou Malnati's",lat:41.87169869,long:-87.62737565)]
restaurant += [PizzaLocation(name:"Lou Malnati's",lat:41.96074325,long:-87.6835484)]
restaurant += [PizzaLocation(name:"Lou Malnati's",lat:41.88411358,long:-87.65808167)]
restaurant += [PizzaLocation(name:"Lou Malnati's",lat:41.85186556,long:-87.72202439)]
restaurant += [PizzaLocation(name:"Lou Malnati's",lat:41.90239382,long:-87.62846892)]
restaurant += [PizzaLocation(name:"Lou Malnati's",lat:41.89031406,long:-87.63388913)]
restaurant += [PizzaLocation(name:"Lou Malnati's",lat:41.92911995,long:-87.65359186)]
restaurant += [PizzaLocation(name:"Lou Malnati's",lat:41.9089214,long:-87.6775678)]
}
}

```

# How to Use MapKit for 2D and 3D Map Views.

Everyone may remember when Apple first introduced MapKit to replace Google Maps on iPhones, they ended up to apologizing. However over time, developers have found how easy it is to use MapKit. This API provides features which make using  both 2D and 3D maps very easy. More importantly, Google charges for map views  over a few thousand views and Apple doesn’t. For many applications requiring a lot of map views or when you have over a few thousand  users,  MapKit might make better sense for a developer not willing to pay the costs for an external API.

In this lesson, we’ll introduce MapKit, and how display a map in both 2d and 3d. We’ll discuss many of the attribute you have in the UIMapView class to make a great map. We’ll also talk about a small cheat using Google maps if you need only a few map points. Along the way I’ll throw in some Chicago history trivia.

# Make a New Project

Start by making a New Single-view  project Called MyMapKitDemo. Use a Universal device and Swift as the language.   When it loads, we need to turn on MapKit.  In the Project Properties, click on the the Capabilities tab.

You will see a list of functions we can use. About halfway down the list you’ll See Maps

Turn on maps and the menu opens.

We won’t be changing anything here, but the framework will load when we need it.

Go to the storyboard.  In the Object Library, find the  Map  Kit View object

Drag it somewhere on the story board.

Select the Map view. Click the   button in the Auto Layout  menu on the lower right of the storyboard. This will bring up the the pin menu. Click off Constrain to margins. Set the margins to be 0 on all sides. Change the Update Frames to Items of New Constraints.  Your pin menu should look like this.

Click Add 4 Constraints. The map view takes the entire view on the story board.

With the map view still selected, look at the attribute inspector.  At the top is some attributes specific to map views:

The Type attribute sets the map to be either  Standard, Satellite or Hybrid, which is combination of the two (a satellite with street names).  The Allows attributes control if the user can use zooming,scrolling rotation or 3D view. By default, the 3D view is on, and we’ll see this is a good thing.  The Shows attributes control extra items on the map. You’ll note User Location is off.  User location shows a dot where the user is. However that dot only shows up if the map shows a region the user happens to be in. Unless you live in the Lincoln Park or Chinatown neighborhoods of Chicago, in our app you won’t be visible.

We’ll be changing a few of these through properties in code. You can leave them alone for now.

Add  seven buttons to the view.  Select all seven buttons.  In the attributes inspector, find the Text color button, and click the color swatch in the button.

A color palette appears. Using the RGB colors, change the color to a Dark Blue (#000088) color.

In the attributes inspector,  scroll down to View.  Click the swatch for the background color. Change the Background to White  #FFFFFF and set the Opacity to 50%

Change the title on the seven buttons to CPOGWrigley, Connie’s, Satellite, 2dMapFlyOver,  and Clean Map. Arrange everything like this.

Select the CPOG,Wrigley and Connie’s buttons.  Click the Stack view Button in the auto layout buttons. In the attributes inspector, change the stack view to a Horizontal Axis, Alignment of Fill, Distribution of Fill Equally and Spacing of 0:

Click the pin button .  Turn off Constrain to Margins. Set the top constraint to 20 points and the left and right to 0 points, leaving the bottom  unchecked. Set Update Frames to Items of New Constraints.

Select the Satellite, 2D Map, Flyover, and Clean Map buttons.  Click the Stack view Button in the auto layout buttons. In the attributes inspector, change the stack view to a Horizontal Axis, Alignment of Fill, Distribution of Fill Equally and Spacing of 0. Click the pin button .  Turn off Constrain to Margins. Set the bottom constraint to 20 points and the left and right to 0 points, leaving the top  unchecked. Update Frames to Items of New Constraints.

Add the three constraints. The final layout looks like this:

We need to wire up the outlets and actions. Go to the ViewController.swift file.  Before we do anything else, MapKit is a separate framework than UIKit.  Just under the `import` `UIKit` add `import` `MapKit`

```import UIKit
import MapKit
```

Once you do that, change the `viewController` class to add all of our outlets and actions:

```class ViewController: UIViewController {
//MARK: Properties and Outlets

@IBOutlet weak var mapView: MKMapView!

//MARK: - Actions

//MARK: Location actions
@IBAction func gotoCPOG(sender: UIButton) {
}
@IBAction func gotoWrigley(sender: UIButton) {
}
@IBAction func gotoConnies(sender: UIButton) {
}

//MARK: Appearance actions
@IBAction func toggleMapType(sender: UIButton) {
}
}
@IBAction func flyoverMap(sender: UIButton) {
}
@IBAction func toggleMapFeatures(sender: UIButton) {
}

//MARK: Instance methods

//MARK: Life Cycle
}
}
```

Go back to the storyboard, and open the assistant editor in Automatic. Drag from the circle next to `gotoCPOG` to the CPOG button on the storyboard. Do the same from `gotoWrigley` to Wrigley, `gotoConnies` to Connie’s, `toggleMapType` to Satellite, `overheadMap` to 2D Map, `flyoverMap` to FlyOver, and `toggleMapFeatures` to Clean Map. Finally, drag from the outlet `mapView` to the mapView.

Build and run. You get a map of the continent you happen to be in.

This is the default setting of a map view – a region that takes in a continent closest to the current location according to the simulator. Since all the attributes were left on, you can pan and zoom on this map.  To zoom on a simulator, hold down the Option key and drag with the mouse.  I zoomed in on Chicago, where we’ll be in the app.

# Getting Sample Location Data From Google Maps

We’ll need some sample location data. I’m going to pick  my favorite baseball field and two favorite pizza restaurants to for this.  MapKit uses several coordinate systems, but the most important is  latitude and longitude. If you need only a few points to test it’s easy to get them by looking up the location in Google Maps. Maps has the location information embedded in the URL for the view.

Go to the web and in Google maps, search for Wrigley Field. If you want the address to search, it’s the one Elwood Blues uses in the Blues Brothers: 1060 W. Addison.

Or you can just go to https://www.google.com/maps/place/Wrigley+Field. When it appears, Click your mouse in the middle of the intersection of Addison and Clark Streets.

If you look at the URL you find something similar to this

`https://www.google.com/maps/place/Wrigley+Field/@41.9472901,-87.6565357,21z/data=!4m2!3m1!1s0x880fd3b2e59adf21:0x1cea3ee176ddd646`

The important part is from the /@ to the next Slash.

`/@41.9472901,-87.6565357,21z`

That’s the map coordinates in latitude and longitude of that intersection. For Apple maps we need one other piece of data: what direction we are pointing, known as the heading. To get that, drop the little guy for Street Siew onto the same intersection, pointing towards the big red Wrigley Field sign.  You get this data

`@41.9471939,-87.6565108,3a,75y,41.73h,90.81t/`

The first two are the map coordinates again. They may not match exactly our first pair.  the important number for us is the heading `41.73h` which tells us the compass direction we are pointing, 41.73 degrees from north.

The three pieces of data we need are latitude 41.9471939 longitude -87.6565108, and heading 41.73 degrees. You can use this method to get coordinates if you have no other way to get the data. In upcoming lessons, we’ll take coordinate data directly from City of Chicago databases and remove this step.

# Core Location Data Types

We represent data for maps in the Core Location data types. Here’s a table to summarize:

CL Type Type Description/Notes
CLDegrees Double A latitude or Longitude
CLDirection Double A heading in degrees based on the distance from North 0 degrees
CLDistance Double A Distance in meters
CLSpeed Double A speed in meters/Second
CLLocationCoordinate2D struct {
var latitude: CLLocationDegrees,
var longitude: CLLocationDegrees,}
A coordinate on a map based on latitude and longitude
CLAccuracy Double The accuracy of a coordinate value in meters.

We’ll use most of these as we build our app. We’d like some way of storing the data we collected from Google Maps in some constants. I made a struct to do that. Add this to `ViewController`.

```//MARK: Location constants
struct cameraInfo{
var location = CLLocationCoordinate2D()
init(
latitude:CLLocationDegrees,
longitude:CLLocationDegrees,
){
self.location = CLLocationCoordinate2D(
latitude: latitude,
longitude: longitude)
}
}
```

We store a `CLLocationCoordinate2D` and a `CLLocationDirection`. To make `location`, we use two `CLLocationDegrees`, one for latitude and one for longitude.

We can use this to save our Wrigley data. Add this to `ViewController` under the struct.

```let wrigleyLocation = cameraInfo(
latitude: 41.9471939,
longitude: -87.6565108,
```

To save you from looking up the two pizza restaurants, I’ll add them for you. Add this  to your code under the `wrigleyLocation`.

```let CPOGLocation = cameraInfo(
latitude: 41.920744,
longitude: -87.637542,
let conniesLocation = cameraInfo(
latitude: 41.849294,
longitude: -87.6414665,
```

# Setting the Map Region

The next step in writing a map app is to set a region. Regions define the visible area based on a center point and a diameter in latitude and longitude. If we were in the real world you think of it as the circle you could visibly see. Since device screens are rectangular, they create a kind of rectangle and set scaling for the map like this.

I said sort of because this is not planar geometry, it’s the spherical geometry of the planet. This region has a type of `MKCoordinateRegion` There is an intializer to get this region, but it uses the differences in map coordinates to define the region. The easier one to use for our purposes is the function `MKCoordinateRegionMakeWithDistance` which takes the three parameters in the illustration above.
We’ll use this function to get the region defined by a radius from the circle, then assign it to our map. Add this to the code as an instance method:

```//MARK: Instance methods
func setRegionForLocation(
location:CLLocationCoordinate2D,
animated:Bool)
{
let span = 2.0 * spanRadius
let region = MKCoordinateRegionMakeWithDistance(location, span, span)
mapView.setRegion(region, animated: animated)
}
```

We set the region in our map view with the `setRegion` method. Since it can be animated we included a parameter in our function to animate the region change. Add this to `viewDidload`:

```setRegionForLocation(
wrigleyLocation.location,
animated: false)
```

When we start our application, we’ll start the application with a radius of 150 meters. Build and run.

There’s the stadium in the upper right. While most people know about the Chicago Cubs, they don’t know about the other team that used to play there, founded by a guy who missed the boat.  In 1915 this guy ran late and  missed the boat for his company picnic. The boat, the Eastland capsized in the Chicago River at the Clark Street bridge killing 855 people.

Five years later, this guy would co-found   American football’s professional league the  NFL. George Halas’  team started playing in Wrigley field in 1922, deriving  their name- The Chicago Bears  – from the baseball team.

# Using Cameras

Besides Papa Bear Halas’ origin story,  what you might not know is this is a 3d map.  You are just looking at it from overhead. In MapKit we use cameras to look at 3d maps. It allows us to change the angle and perspective we are looking at the object.  Change the `flyoverMap` action to this:

```@IBAction func flyoverMap(sender: UIButton) {
let camera = MKMapCamera()
camera.centerCoordinate = mapView.centerCoordinate
camera.pitch = 80.0
camera.altitude = 100.0
mapView.setCamera(camera, animated: true)

```

The `camera` property of MapKit is the view we see of the map. It has four properties, which we set all of them in this method. The `centercoordinate` is a coordinate the camera centers its view. `pitch` is the angle up or down of the camera. `altitude` is how high in the air is the camera. `heading` is the compass direction the camera faces. We set this camera 80 degrees from vertical, 100 meters in the air with a heading northeast. Build and run. Tap the Flyover button and you get the following in the simulator.

If you run on a phone instead of a simulator, you get a more robust image, with 3d buildings.

While you can set all three camera properties on your own, you can also use a few methods as well. Change the `gotoCPOG` action to this:

```@IBAction func gotoCPOG(sender: UIButton) {
let camera = MKMapCamera(
lookingAtCenterCoordinate: CPOGLocation.location,
fromDistance: 0.01,
pitch: 90,
mapView.setCamera(camera, animated: true)
}
```

Here we use the initializer `MKMapCamera:lookingAtCenterCoordinate:fromDistance:pitch:heading:` method. We use the `CPOGLocation.heading` to get the heading.   This method just takes all our properties and makes a camera that is 1 centimeter from the location, pitching the camera at the horizon, and setting the heading according to our constant . This should be close to a human’s eye view.

This location is in front of Chicago Pizza and Oven Grinder, the inventors of the bowl pizza. Ingredients are placed in a ceramic bowl and the crust is placed over the top of the bowl. The bowl is baked and then inverted, making a pizza. There’s something else about this location, but build and run first. Click The CPOG button. On the simulator you get this:

On a phone, you’ll find the iPhone is more robust with graphics  than the simulator.:

First one more bit of Chicago history. You’ll notice a inset from the buildings I marked with a red arrow.

There’s a gap between the buildings that’s now a parking lot. There was a garage there once. This was the site of the infamous St. Valentines Day Massacre.  The blue arrow is Pizza and Oven Grinder at 2121 N. Clark, and legend has it Jack McGurn, Al Capone’s lieutenant rented a room on the second floor a few weeks before the massacre to scope out the garage.

Okay enough history. You’re probably noticing the big software problem. We should be getting a human’s eye view pf the street. Instead we get a pigeon.  This is one of the problems with Apple Maps in 3D: there is a minimum altitude that’s about 30 meters. Apple didn’t call it flyover for nothing. On a phone if you two-finger drag up, and you notice the display does not want to pitch any more.

## 2D Views Revisited

If the code gets a value that makes no sense from a 3Dview, it places a 2D view instead.  We can see this with  another way of positioning the camera. This method takes a center coordinate, a coordinate for the camera and an altitude. It finds the pitch by doing math to the eye coordinate and altitude.  Add this code

```@IBAction func gotoWrigley(sender: UIButton) {
let camera = MKMapCamera(
lookingAtCenterCoordinate: wrigleyLocation.location,
fromEyeCoordinate: wrigleyLocation.location,
eyeAltitude: 200)
mapView.setCamera(camera, animated: true)
}
```

This code uses the same two coordinates for the location.  With the same two coordinates, MapKit makes the camera into a overhead camera. Build and run, then press the Wrigley button

All we’ve done is zoom in on our Wrigley coordinates.  Change the action to this:

```@IBAction func gotoWrigley(sender: UIButton) {
var eyeCoordinate = wrigleyLocation.location
eyeCoordinate.latitude += 0.005
eyeCoordinate.longitude += 0.005
let camera = MKMapCamera(
lookingAtCenterCoordinate: wrigleyLocation.location,
fromEyeCoordinate: eyeCoordinate,
eyeAltitude: 50)
mapView.setCamera(camera, animated: true)
}
```

We increased our eye coordinate to be 0.005 degrees north and 0.005 degrees west of the center coordinate. Build and run. When we tap the Wrigley button now, we get this in the simulator:

We’ve moved around to the northeast  corner of the ballpark. Using this method, the heading will always be  looking at the  center coordinate, in this case  Clark and Addison.

Another way to show a 2Dmap by camera is set the `pitch` to 0. Add this code:

```@IBAction func gotoConnies(sender: UIButton) {
let camera = MKMapCamera(
lookingAtCenterCoordinate: conniesLocation.location,
fromDistance: 1300, pitch: 0,
mapView.setCamera(camera, animated: true)
}
```

When you  build, run and try the Connie’s button, you get this:

Connie’s Pizza marks mile 21 of the Chicago Marathon, one of the flattest courses  and oddly the highest average elevation (590m) of the six major league marathons. If you want to set world records for running 26.2 miles or get that Boston Qualifier, this is the race to do it, and many do.

You can of course set the map view’s camera directly. Add this code to show a 2D map of any point,  at an attitude of 1000 meters.

```@IBAction func overheadMap(sender: UIButton) {
mapView.camera.pitch = 0.0
mapView.camera.altitude = 1000.0
}
```

Build and run. First show CPOG as a 3D map, then click the 2D Map button.

Clark is a diagonal street heading northwest out of Chicago. It may be a good idea to set `heading` to 0 and show north as up. Change the code to this

```@IBAction func overheadMap(sender: UIButton) {
mapView.camera.pitch = 0.0
mapView.camera.altitude = 1000.0
}
```

Now you get something that makes more sense as a static map on a phone:

# Using Satellite Imagery

In MapKit there are three types of maps: Standard, Satellite and Hybrid.  Standard is the default type we’ve been using already. Satellite gives satellite imagery, but no road information. Hybrid combines the road information of standard with the satellite image.

We control the map type with the `maptype` property.  Add this to the `gotoConnies` action.

`mapView.mapType = .Satellite`

Now run the app, and tap the Connie‘s button. you get a satellite overhead map.

Change `.Satellite` to `.Hybrid` and you get this

You can easily see both the pizza icon for my favorite pizza in Chicago and the  south branch of the Chicago river in this photo.  The south branch of the Chicago river is part of one of the marvels of modern engineering: it flows backwards from its natural course.  The river flow project, completed in 1900, reverses the river flow so sewage flows down to the Mississippi River  entering not far from St. Louis  instead of into Chicago’s water supply of Lake Michigan. Just In case you are worried, Chicago now cleans their water before they do that today.

## Satellite and Flyover

That’s however is not the whole story. To use flyover 3d on a satellite or hybrid map there are two more types: `.SatelliteFlyover` and `.HybridFlyover`.  Change  `gotoWrigley`, to this

```@IBAction func gotoWrigley(sender: UIButton) {
var eyeCoordinate = wrigleyLocation.location
eyeCoordinate.latitude += 0.004
eyeCoordinate.longitude += 0.004
let camera = MKMapCamera(
lookingAtCenterCoordinate: wrigleyLocation.location,
fromEyeCoordinate: eyeCoordinate,
eyeAltitude: 50)
mapView.mapType = .HybridFlyover
mapView.setCamera(camera, animated: true)
}```

I moved in the coordinates a bit more to get a better look at the ballpark. Build and run. Tap the Wrigley button. You get this on a phone:

So you can experiment with the different types and what they will do, let’s add some code to toggle the type. Change the `toggleMapType` to this

```@IBAction func toggleMapType(sender: UIButton) {
let title = sender.titleLabel?.text
switch title!{
case "Satellite":
mapView.mapType = .Satellite
sender.setTitle("Hybrid", forState: .Normal)
case "Hybrid":
mapView.mapType = .Hybrid
sender.setTitle("Standard", forState: .Normal)
case "Standard":
mapView.mapType = .Standard
sender.setTitle("Satellite", forState: .Normal)
default:
mapView.mapType = .Standard
sender.setTitle("Satellite", forState: .Normal)
}
}
```

We use a `switch` statement from the `titleLabel.text` of the button to toggle between the types. These are the 2d types for `.Satellite` and `.Hybrid`. We need a little code to to use the 3d types when we turn on flyover.  Change the `flyoverMap` action to this.

```@IBAction func flyoverMap(sender: UIButton) {
//change to the correct type for flyover
switch mapView.mapType{
case .Satellite:
mapView.mapType = .SatelliteFlyover
case .Hybrid:
mapView.mapType = .HybridFlyover
case .Standard:
mapView.mapType = .Standard
default:
break
}

let camera = MKMapCamera()
camera.centerCoordinate = mapView.centerCoordinate
camera.pitch = 80.0
camera.altitude = 100.0
mapView.setCamera(camera, animated: true)
}
```

Build and run. Try a few combinations of the buttons. Here’s a one minute video if you don’t have a phone handy.

The time to render some of these images is rather long. There’s a lot of processing and data transmission. Each location changes the region dramatically, so everything has to load over again. The rendering time is short only for the `.Standard` flyover version. Keep this in mind as you are using these types.

# Toggling features

While `.Satellite` tuns off all the features like attractions, rendering buildings and the like, there are a few properties you can use in the `.Standard` mode to control these. Change `toggleMapFeatures` to this

```    @IBAction func toggleMapFeatures(sender: UIButton) {
let flag = !mapView.showsBuildings
mapView.showsBuildings = flag
mapView.showsScale = flag
mapView.showsCompass = flag
mapView.showsTraffic = flag
}

```

Play with this a little.  Go to Connie’s Pizza and set to `.Standard` Mode. Tap Clean Map. Everything but road names disappears.

Tap Busy Map.  We get back our attractions, plus the scale and traffic.

You’ll notice the compass doesn’t show. When the `.heading` is 0. there is no compass. If the user rotates the map, then the compass will show.

Tap Flyover and we get the 3d view with buildings

Tap Clean Map and we get just the roads and river.

Play around with these. You may find some of the combinations don’t work. Some of the `mapType`s set and use these features in specific ways. Check the  MKMapView Class Reference for more information.

You can display a lot of information through a map view. We’ve seen that coding a map in 2d or 3d is not that difficult as long as you have some coordinate data. We’ve also seen that Apple provides a lot of attractions such as restaurants and sports stadiums for you. We have not yet added our own locations and features, known as annotations and overlays. In our next lesson, we’ll take a 2d map and annotate it with some data.

# The Whole Code

```//
//  ViewController.swift
//  MyMapKitDemo
//
//  Created by Steven Lipton on 5/4/16.
//

import UIKit
import MapKit

class ViewController: UIViewController {
//MARK: Location constants
struct cameraInfo{
var location = CLLocationCoordinate2D()
self.location = CLLocationCoordinate2D(latitude: latitude, longitude: longitude)
}
}

let wrigleyLocation = cameraInfo(latitude: 41.9471939, longitude: -87.6565108, heading: 41.73)
let CPOGLocation = cameraInfo(latitude: 41.920744, longitude: -87.637542, heading: 338.0)
let conniesLocation = cameraInfo(latitude: 41.849294, longitude: -87.6414665, heading: 32.12)
//MARK: Properties and Outlets
@IBOutlet weak var mapView: MKMapView!
//MARK: - Actions

//MARK: Location actions

@IBAction func gotoCPOG(sender: UIButton) {
mapView.setCamera(camera, animated: true)
}

@IBAction func gotoWrigley(sender: UIButton) {
var eyeCoordinate = wrigleyLocation.location
eyeCoordinate.latitude += 0.004
eyeCoordinate.longitude += 0.004
let camera = MKMapCamera(lookingAtCenterCoordinate: wrigleyLocation.location, fromEyeCoordinate: eyeCoordinate, eyeAltitude: 50)
mapView.mapType = .HybridFlyover
mapView.setCamera(camera, animated: true)
}

@IBAction func gotoConnies(sender: UIButton) {
let camera = MKMapCamera(lookingAtCenterCoordinate: conniesLocation.location, fromDistance: 1300, pitch: 0, heading: 0.0)
mapView.mapType = .Hybrid
mapView.setCamera(camera, animated: true)
}

//MARK: Appearance actions

@IBAction func toggleMapType(sender: UIButton) {
let title = sender.titleLabel?.text
switch title!{
case "Satellite":
mapView.mapType = .Satellite
sender.setTitle("Hybrid", forState: .Normal)
case "Hybrid":
mapView.mapType = .Hybrid
sender.setTitle("Standard", forState: .Normal)
case "Standard":
mapView.mapType = .Standard
sender.setTitle("Satellite", forState: .Normal)
default:
mapView.mapType = .Standard
sender.setTitle("Sat Fly", forState: .Normal)
}
}

mapView.camera.pitch = 0.0
mapView.camera.altitude = 1000.0
}

@IBAction func flyoverMap(sender: UIButton) {
switch mapView.mapType{
case .Satellite:
mapView.mapType = .SatelliteFlyover
case .Hybrid:
mapView.mapType = .HybridFlyover
case .Standard:
mapView.mapType = .Standard
break
default:
break

}

let camera = MKMapCamera()
camera.centerCoordinate = mapView.centerCoordinate
camera.pitch = 80.0
camera.altitude = 100.0
mapView.setCamera(camera, animated: true)
}

@IBAction func toggleMapFeatures(sender: UIButton) {
let flag = !mapView.showsBuildings
mapView.showsBuildings = flag
mapView.showsScale = flag
mapView.showsCompass = flag
mapView.showsTraffic = flag
mapView.showsPointsOfInterest = flag
if flag {
sender.setTitle("Clean Map", forState: .Normal)
} else {
sender.setTitle("Busy Map", forState: .Normal)
}
}

//MARK: Instance methods
let span = 2.0 * spanRadius
let region = MKCoordinateRegionMakeWithDistance(location, span, span)
mapView.setRegion(region, animated: animated)
}

//MARK: Life Cycle
}
}

```

Even if you never want to make an app for the Apple Watch, there’s one place you might want to think about supporting: Notifications. In a previous lesson, we explored how to make local notifications for iOS devices. That lesson ended with a free bonus: If a phone is sleeping and you have an Apple Watch, the notification will go to the watch.

Starting in iOS8, notifications get one big change: they can have actions of their own. On phone, tablet or watch this gives you more flexibility in how to respond to a notification. Suppose you had an app that after an appointment comes up, nags you about it every ten seconds until you stop the nagging. You could of course go into the app and shut it off, but it might be easier to have a stop nagging button on the notification. In this lesson, we’ll make that stop nagging button first for iOS devices, then for the Apple Watch. Along the way we’ll discover why watch notifications are the one place iOS developers should seriously think about for their phone apps.

# Making a Demo Program – A Review of Notifications

In a previous lesson we went into detail about local notifications. We’ll be using a lot of what was learned there. In this tutorial, we’ll build a simple app to make a series of notifications similar to the HIIT app at the end of that lesson. We’ll use this as a review and quick introduction to local notifications if you are not familiar with them.

Since we will eventually get to some watch related notifications, make a new project using the iOS with Watch OS App template.

Name the project PhoneWatchNotificationDemo and make sure watch notifications is checked on and everything else is off.

Once you save the project, add a new file by pressing Command-N called NaggyNotification subclassing `NSObject. `Add these properties to the class

```class NaggyNotification: NSObject {
private let basicNags = ["Nag", "Nag nag","Naggity nag"]
private let emojiNags = ["😀","😉","🙄","😒","😠","😡"]
private var nags = ["Nag", "Nag nag","Naggity nag"]
private var counter = 0
private var timer = NSTimer()
var nagging:Bool {return timer.valid } //read only
}
```

If you don’t know how to type emojis, press Control-Command-Spacebar to get the symbols palette.

We are going to do something insane a little later with this class. To protect against some of the problems with that, all but one of our properties is `private` and inaccessible outside the class. There is one read-only property `nagging` which uses a computed read-only value.

Most of these properties we’ll get to. We’ll start with the most important. The `localNotification` will contain our notification. Add the following method to present it immediately:

```    func presentNotificationNow(){
}
```

There are two ways to present notifications. We can present immediately as we do with the `presentLocalNotificationNow` method above or at some scheduled time in the future with the `scheduleLocalNotification` method. We could schedule that time using the `fireDate` property of `UILocalNotification`, but that presents a problem. We can only schedule 64 notifications, which in a nagging app might be too little space. We will take a different approach: Use a `NSTimer` loop in the background. Add the following method to start a timer:

```func startTimer(timeInterval:NSTimeInterval){
if !timer.valid{ //prevent more than one timer on the thread
counter = 0
timer = NSTimer.scheduledTimerWithTimeInterval(
timeInterval,
target: self,
selector: #selector(timerDidFire),
userInfo: nil,
repeats: true)
}

}
```

We do three things in this code. We reset a counter for counting how many nags the user has been subjected to, then set this task into the background. While on a simulator you can leave things in the background without this, your app will suspend operation without `beginBackgroundTaskWithExpirationHandler` on a live device. Finally we start a timing loop, getting the timing interval from the parameter `timeInterval`. The timing loop ends on a selector `timerDidFire`. Let’s add the code for `timerDidfire`. Add this to the class:

```    func timerDidFire(timer:NSTimer){
counter += 1
let currentNag = counter % nags.count //cycle through messages
let nagString = String(format:"# %i %@",counter,nags[currentNag])
}
```

If you are not familiar with timing loops you might want to refer to this lesson. Basically, the `timer` object is set to run the `timerDidFire` function every `timeInterval` seconds. Once in the `timerDidFire` function, we increment `counter` and compose a string we’ll post to the notification. The property `alertBody` of `UILocalNotification` sets the text for the notification. We also set the sound to the default sound, which will also set off vibrations and haptics. For later use, we all send a dictionary containing our count and our current nag as `userInfo` we can use later in this lesson. Finally we present the notification.

We’ll also need a way to shut down the timer. Add this method to your code:

```func stopTimer(){
timer.invalidate()
}
```

We shut down the timer and remove the task from the background.

Now for the small, but insane bit of code. Add this above the class declaration:

```let naggingNotification = NaggyNotification()

...```

A variable declared outside a class is global. Global values or instances can be used anywhere in the target code. There are other, better ways of handling the `NaggyNotification` class, but I could write full tutorials on them. As we’ll see, this instance will show up in several classes. This is a simple way to get it into all of them. As I always do when I use a global, I warn people not to use globals except in special circumstances. They are notoriously hard to track down in code. It’s why I made all the properties private, only methods are accessible to other classes, which are easier to deal with.

In order to use a notification, you must tell the application you will be using the notification in the AppDelegate.swift file. Go to the AppDelegate class Change the `application:didFinishLaunchingWithOptions:launchOptions:` method to this:

``` func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
categories: nil
)
)
return true
}
```

We register the notification settings for the two types of notifications: Alerts(or banners) and sounds(or haptics and vibrations).

Our app has all the internal parts set, we need a user interface. We’ll make a very simple one of a single button. Go to the ViewController.swift file. Change `ViewController` to this:

```class ViewController: UIViewController {
@IBOutlet weak var nagButton: UIButton!
@IBAction func nagButton(sender: UIButton) {
}
}
```

We’ll have one button that we’ll assign a outlet and action to. Change the `nagButton` action to this:

```@IBAction func nagButton(sender: UIButton) {
}else{
}
stateDidChange()
}
```

This code uses the `naggingNotification` read-only property `nagging` to determine if the timer is on. We toggle the timer depending on the result, using the `naggingNotification` methods `stopTimer` and `startTimer`. We’ve set up this demo with a 10 second timer.

Our last statement calls a method we have yet to define `stateDidChange()`. We’ll update the button title with this. Add this code to `ViewController`:

```func stateDidChange(){
nagButton.setTitle"Nag", forState: .Normal)
}else{
nagButton.setTitle("Stop Nagging", forState: .Normal)
}
}
```

We have our code. Go to the storyboard. Drag one button to the center of the storyboard. Title it Nag, and set the font to 46 point Bradley Hand.

In the lower right corner of the storyboard, you will find the auto layout controls. With the Nag button selected, click the align icon to get the align menu. Towards the bottom of this menu you will find the center Horizontally in Container and Vertically in container settings. Click both on with values of zero. Set the Update frames to Items of New constraints.

Open the assistant editor. Drag from both circles in the code to the button to connect the action and the outlet to the button.  Close the assistant editor.

Before we test this, launch both the iPhone and watch simulators. If you have never launched these before running an app, check the directions here Especially with the watch, it helps to have them running before you run an app on them.

Build and run using a iPhone 6s plus simulator. You get the notification message the first time you run this:

Press OK to allow notifications.You get a simple screen of a single button:

Tap the Nag button.

The button toggles but doesn’t do more than that. we need to be outside the app to see a notification.

Press Command-Shift-H or on the hardware simulator menu, Hardware>Home. Wait a few seconds and you will see this:

Swipe down from the status bar once the banner disappears. Select Notifications and you will see the notifications appear.

Tap one of the notifications and you are back in the app. Tap Stop Nagging and the notifications turn off.

Introduced in iOS8, Notifications  now have their own actions, which appear as buttons on a notification. Often you’ll find these in the `AppDelegate`.  I’ll however keep everything on one class for the notification. Actions are of class `UIUserNotificationAction` and it’s subclass `UIMutableUserNotificationAction`. Since you can’t change anything in a `UIUserNotificationAction`, we define actions in `UIMutableUserNotificationAction`s. We’ll define two actions, one to stop the timer and one to change the nag message to emoji. In the `NaggyNotification` class add the following method:

```func makeActions()-> [UIMutableUserNotificationAction]{
stopAction.title = "Stop"
stopAction.identifier = "StopAction"
stopAction.destructive = true
stopAction.authenticationRequired = true
stopAction.activationMode = .Foreground

moreAction.title = "Emoji"
moreAction.identifier = "EmojiAction"
moreAction.destructive = false
moreAction.authenticationRequired = false
moreAction.activationMode = .Background

return [stopAction,moreAction]
}
```

The `title` parameter is the title that will appears on buttons of the notification. The `identifier` is the string used to internally identify the action. You’ll notice that there is no code here to execute the action. We’ll use that identifier to code the action in `AppDelegate`. We can add a red warning to a button if it is a `destructive` button, one that deletes something. I used it here as the Stop button, but left `destructive` as `false` for the Emoji button. The `activationMode` has two choices:` .Foreground` or `.Background` and indicates if the app will execute the action in the foreground or the background. To maintain security of the user’s phone we can also require an authentication before we execute the action. For actions in the foreground, this is mandatory and `activationMode` is always true. The statement in our code is redundant.

We return an array of the actions. We will use these actions in a category. Categories contain all information about a specific type of notification. Our category, which we’ll call Nags contains the actions that will show in the nag notification. Add the following code to the `NaggyNotification` class.

``` //MARK: - Categories and Actions
category.identifier = "Nags"
category.setActions(makeActions(), forContext: .Default)
return category
}
```

We make set two properties on a `UIMutableUserNotificationCategory`. We set an identifier Nags and using the` setActions:forContext:` method add the actions to the category.

We’ve set up our category and actions. Now to use them. We’ll do that in `AppDelegate`. Find the method we changed earlier. Change the highlighted lines to add the category to our current code.

```func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) ->; Bool {
// Override point for customization after application launch.
categories: [category]
)
)
return true
}
```

If we ran our code now, we would have our actions listed in the notification, but nothing would happen. We need to add a callback method to `AppDelegate` containing the code to execute the actions. Add this to `AppDelegate`

```    func application(application: UIApplication, handleActionWithIdentifier identifier: String?, forLocalNotification notification: UILocalNotification, completionHandler: () -> Void) {

if identifier == "StopAction"{
}
if identifier == "EmojiAction"{
}
}
completionHandler()
}

```

The `application:handleActionWithIdentifier:forlocalNotification` method has a `actionIdentifier` and a UILocal`Notification`. for parameters.   The code checks the notification’s title. If it is our notification, we check the action identifier and perform the action we need.

We need one more method back in `NaggyNotification` to toggle the alert messages. Add this to the code.

```func toggleAlertMessages(){
if nags == basicNags {
nags = emojiNags
} else {
nags = basicNags
}
}
```

## Fixing a Bug Before It Happens

This is all the code we need to run our application. However, there’s one bug that we’ll fix first. The problem is the Stop action when we are in the background. It will stop the the timer and shut down the nags. The button on our view controller does not know this. With the code as it is written the button still says Stop Nagging when we enter the foreground. We need to update the button any time we do enter the foreground. Find the `applicationDidBecomeActive` in `AppDelegate`. This method runs when we need to do that refresh of our user interface. Change it to this

```    func applicationDidBecomeActive(application: UIApplication) {
let rvc = window?.rootViewController as! ViewController
rvc.stateDidChange() //Update the button
}
```

Line 2 of the code gets the view controller. We have the view controller as our root view controller, so it’s easy to access. Once we have a reference to the root controller, we can call its method. `statDidChange` which checks the status of the timer and changes the title to the correct one.

Build and run.

Press the nag button. Press Command-Shift-H. Eventually the notification appears:

Drag the small oval at the bottom of the notification down.

The actions appear.

Tap the emoji button.  The next notification you get is an emoji.

Drag down from the status bar and get the notifications. Swipe right to left on one of the notifications.

Tap the Stop button. The app stops and opens up to the Nag screen again.

# The Apple Watch for All Developers

While that’s what you need to know for iOS, it’s not the whole story. Unless notifications are turned off by the user of an Apple watch, the watch will receive the notification if the phone is asleep.  Sadly, the watch simulator does not always reflect what happens on the watch.  You can try using the simulator if you  don’t have a watch handy, I’ll be using both since they have slightly different behaviors.

If your app is still running, get the watch and phone  simulator visible

Start nagging with the phone, then press Command-L to Lock the phone. The simulator goes black. Wait a few seconds,  And you will see the Short-Look Notification appear:

A second later, the  Long-Look notification appears.

You’ll notice the buttons for the actions don’t quite fit on the watch. scroll up and you’ll find one more button.

Test the emoji button.  Tap it, and the next notification changes to this:

Press the stop button and you get a blank screen with the time. Actually, you are running a blank watch app.

You get slightly different  results with a real phone. Running the app on my phone, I start nagging by pressing the Nag button. I then lock my phone  by pressing the switch. SInce I turned on sounds and used the system sound in my actions, I’ll get a Haptic vibration on my wrist,  and then the notification.

The notification includes the Emoji button and a dismiss button, which is cut off.  You can scroll up to get the rest of the dismiss button. On the simulator, we had the stop button, but on the watch it’s missing.

The difference has to do with `activationMode`. If you have an action with an `activationMode` of `.Foreground `the watch does not display it automatically. The foreground mode on the watch starts the watch app associated with this notification. In the simulator it lets us run that blank app, but on a physical watch it knows there is no app and doesn’t show the button.  On the other hand, an `activationMode` of `.Background` on the watch sends to the background of the phone. That’s why with no coding, the Emoji button works perfectly. Go to the `NaggyNotification` class. In `makeActions`, change our code to put the Stop button in the background

`stopAction.activationMode = .Background`

Now run the app again and when we lock the phone we get both buttons on the watch:

With more buttons, the dismiss button is missing. Drag up and you will find it:

Tap the Emoji Button. The next notification changes to emoji

Tap the Stop button. On both the live watch and the simulator, the timer stops.  All of our actions work on the watch without a single new line of code.

Notifications will happen on an Apple Watch even if you don’t program for it. For Apple watch developer, this provides one way to launch your watch app. For iOS developers using notifications and actions, it means you have one more thing to think about when writing an app.  Think out what you want to show and not to show  for a watch user. If you are not writing a watch app, you can exclude actions from the watch but not the phone by making the  `activationMode` go to the foreground.

# The whole code

```//
//
//  Created by Steven Lipton on 5/1/16.
//

import UIKit

//Global variable -- not always a good idea,
// but makes running this code much simpler
//

//All properties are private or read only
//Good insurance for using the global instance
//nothing gets messed up.

private let basicNags = ["Nag", "Nag nag","Naggity nag"]
private let emojiNags = ["😀","😉","🙄","😒","😠","😡"]
private var nags = ["Nag", "Nag nag","Naggity nag"]
private var counter = 0
private var timer = NSTimer()
var nagging:Bool {return timer.valid } //read only

}
if nags == basicNags {
nags = emojiNags
} else {
nags = basicNags
}
}

func startTimer(timeInterval:NSTimeInterval){
if !timer.valid{ //prevent more than one timer on the thread
counter = 0
timer = NSTimer.scheduledTimerWithTimeInterval(
timeInterval,
target: self,
selector: #selector(timerDidFire),
userInfo: nil,
repeats: true)
}

}

func timerDidFire(timer:NSTimer){
counter += 1
let currentNag = counter % nags.count //cycle through messages
let nagString = String(format:"# %i %@",counter,nags[currentNag])

}

func stopTimer(){
timer.invalidate()
}

//MARK: - Actions and Categories
stopAction.title = "Stop"
stopAction.identifier = "StopAction"
stopAction.destructive = true
stopAction.authenticationRequired = true
stopAction.activationMode = .Background

moreAction.title = "Emoji"
moreAction.identifier = "EmojiAction"
moreAction.destructive = false
moreAction.authenticationRequired = false
moreAction.activationMode = .Background

return [stopAction,moreAction]
}

category.identifier = "Nags"
category.setActions(makeActions(), forContext: .Default)
return category
}
}

```

## AppDelegate.swift

```//
//  AppDelegate.swift
//
//  Created by Steven Lipton on 5/1/16.
//

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?

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

if identifier == "StopAction"{
}
if identifier == "EmojiAction"{
}
}
completionHandler()
}

func applicationDidBecomeActive(application: UIApplication) {
let rvc = window?.rootViewController as! ViewController
rvc.stateDidChange() //Update the button
}

}

```

## ViewController.swift

```//
//  ViewController.swift
//
//  Created by Steven Lipton on 5/1/16.
//

import UIKit

class ViewController: UIViewController {
@IBOutlet weak var nagButton: UIButton!
@IBAction func nagButton(sender: UIButton) {
}else{
}
stateDidChange()
}
func stateDidChange(){
nagButton.setTitle("Nag", forState: .Normal)
}else{
nagButton.setTitle("Stop Nagging", forState: .Normal)
}
}
}```

The word notification gets a bit abused in the world of mobile development, especially in the world of Apple development. Notifications could mean internal notifications, where classes use observers to watch unrelated code. When a notification appears, the observer code executes special code for that event.

Another type of notification notifies a user that something has happened, even if they are not in the app the sent the notification – or the device  is sleeping. That kind of user notification has two varieties: push notifications and local notifications. To  the user, these two are the same. For the developer, the push notification uses an external server to push data from the outside world. The Messages app, Facebook and Twitter all use push messages. Due to using an external server, things get complicated with push notifications. There is a registration process with Apple, extra libraries to use them, and you have to write or import code to handle the server data.

The much simpler local notification needs none of that. With a few lines of code, you can fire off a notification. Often used on scheduling and timer applications, this can adapt for many other uses where external data isn’t necessary. In this lesson, we’ll look at the local notification. We’ll make a HIIT timer app to show aspects of the local notification.

# Set Up a New Project.

Start a new single view project called SwiftLocalNotificationDemo with Swift as the language and a Universal device.  Save the file, and then go to the story board. We’ll eventually use a navigation controller for this app. Select the existing view controller and from the menu select Editor>Embed in>Navigation Controller.  You’ll have a navigation controller and a view controller on the storyboard.

On the storyboard add three buttons,  three labels  and a segmented control.  Arrange them roughly like this.

Set the titles and text like this for the controls.

I added color an fancied it up. You don’t have to do this step, but it makes it a bit nicer to look at. I used a palette of #220066 for the dark  and #FFDDFF for the light. I also changed up and down for symbols.  Use the keyboard shortcut  Control-Command-Space to get the symbol popup.

## Using Stack Views

We’ll use some embedded stack views to align everything quickly.  I’m not going to explain stack views here, but for those who have never used them, I’ll go step by step. If you are interested you can read this about them or go buy my book on auto layout. Select the Seconds and 00 labels  On the bottom right of the story board, You’ll find the auto layout controls.

Click the stack view icon. It immediately makes a stack view of the two labels.  Select the two arrows and the seconds stack view.

Click the stack view button again. The three combine into one stack view.

Select everything on the storyboard. Hit the stack view button again. Now everything is one stack view.

Find the pin button in the auto layout controls. In the popup that appears, pin all four sides 10 points in the popup. Also set the Update Frames with Items of New Constraints.

Add the 4 constraints. Depending on where your controls were, th storyboard now looks something like this.

You’ll notice in the attributes inspector the stack view attributes. Change them to An axis of Vertical, Alignment of Fill and Distribution of Fill Equally:

Open the document outline. Open up all the arrows so you can see the hierarchy of the stack views. It’s a lot easier to click on the document outline than the storyboard to select stack views.  Select the second stack view down.

In the attributes inspector, change the stack view to this:

Select the last stack view.

Change the attributes to this:

You now have a storyboard  looking like this:

Select the Seconds and 00 labels. Center align them.

We now have a fully aligned layout.

# Setting Up the Code

Go to the ViewController.swift code.  Add the following outlets and actions.

```//MARK: - Outlets
@IBOutlet weak var statusLabel: UILabel!
@IBOutlet weak var workoutType: UISegmentedControl!
@IBOutlet weak var secondsIndicator: UILabel!
//MARK: - Actions
@IBAction func upArrow(sender: UIButton) {
}
@IBAction func downArrow(sender: UIButton) {
}
@IBAction func setInterval(sender: UIButton) {
}
```

Go back to the storyboard and open the assistant editor. Drag from the circle next to `statusLabel` to The Quick HIIT Timer Label. Drag from the circle to the left of `secondsIndicator` to the 00 label. In the same way Connect `workoutType` to the segmented control, `upArrow` to the up arrow(Up) button, `downArrow` to the down arrow(Down) button, and `setInterval` to the Set Interval button. Close the assistant editor and go to the Viewcontroller.swift code. Above the outlets, add a property:

``` //MARK: Properties
var seconds:NSTimeInterval = 0.0
```

We’ll use the up and down buttons to change a counter `seconds`. Change the actions `upArrow` and `downArrow` like this:

```@IBAction func upArrow(sender: UIButton) {
seconds += 1.0
secondsIndicator.text = displaySeconds()
}
@IBAction func downArrow(sender: UIButton) {
seconds -= 1
if seconds < 0{
seconds = 0.0
}
secondsIndicator.text = displaySeconds()
}
```

In these actions, our last statement sends the current seconds to the label. It converts the time interval to a string in a function `displaySeconds`. Add `displaySeconds` to your code:

```//MARK: Instance Methods
func displaySeconds() -> String{
let mySeconds = String(format:"%02i",Int(seconds))
return mySeconds
}
```

We now have a working counter in our app. Add the following code to `setInterval`.

```@IBAction func setInterval(sender: UIButton) {
//make a status string
let index = workoutType.selectedSegmentIndex
let workout = workoutType.titleForSegmentAtIndex(index)!
let status = displaySeconds() + " seconds " + workout
statusLabel.text = status + " set"
}
```

Nothing visible happens when we schedule a notification. We now have some feedback of what notification we just set.

We’re ready to set a local notification. Add some more code to the `setInterval` action

```@IBAction func setInterval(sender: UIButton) {
//make a status string
let index = workoutType.selectedSegmentIndex
let workout = workoutType.titleForSegmentAtIndex(index)!
let status = displaySeconds() + " seconds " + workout
statusLabel.text = status + " set"

}
```

Line 9 of this code makes an instance `localNotification` of the `UILocalNotification` class. Local notifications can be immediate or time based. We set the time we will launch the notification, its `fireDate`, with an `NSDate` object. If this was a scheduling app I’d set the scheduled time for the notification to fire. In line 10 I want a time `seconds` in the future from now. The `alertBody` property of line 11 sets the message that will appear on the notification. We show we completed that interval. While not mandatory, since we are using a time, we set the time zone the notification will use for its clock, usually the default time zone for the system.

Our last line of code in line 14 is the first of two tricky things about notifications. The notification isn’t running in our class. Instead, it’s part of a bigger structure within the device’s OS. If the app isn’t running in the foreground, we get our notification. The object `UIApplication.sharedApplication()` is the application object we need to schedule this with. We schedule that notification with `scheduleLocalNotification`.

The second tricky part is we tell the `UIApplication` object we are using notifications and how we will be using them. We do that in its delegate, the often ignored `AppDelegate`. Go to the AppDelegate.swift file in Xcode. Toward the top, you’ll find the `application:didFinishLaunchingWithOptions:LaunchOptions:` method. Add the highlighted code:

```func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
categories: nil
)
)
return true
}
```

We register our notification with a `UIUserNotificationSettings` object. We have two parameters to set in the `UIUserNotificationSettings` object: the type of notification and the actions we might take. These actions are known as categories. We’ll discuss categories in our next lesson, so we set `categories` to `nil` and focus on types. There are four types available to us:

• `.Alert` sends an alert or banner
• `.Sound` plays a sound
• `.Badge` shows the small red dot with a counter on the app icon
• `.None` which does not present a notification.

We set up all three notifications. We are ready to build and run. As soon as the launch screen disappears from the app we see the alert:

Notifications are one feature that the user chooses. Tap OK. Tap the up arrow until the counter reads 15 seconds.

Tap the Set Interval button. The status tells us we added an interval.

Press Command-Shift-H to go to the home screen. In a few seconds, the interval will fire and you’ll see the notification.

Go to the Settings app in the simulator. Scroll down towards the bottom and you’ll find our app.

Select the SwiftNotificationDemo entry in Settings and we find one entry  for Notifications.

Click that and we get the standard notifications settings page. Currently it is at its default settings.

Toward the bottom you’ll  find the Alert Style When Unlocked setting. Change it from Banners to Alerts.

Now go back to the app. Let’s do this and demonstrate one more feature of notifications. Swipe down from the top of the screen to get the notification center.

Tap the notification. You are back in the app. Notifications when tapped launch the app or bring the app to the foreground.

Tap the Set Interval again, then press Command-Shift-H to go back to the home screen. Wait, and you get an alert style notification.

Unlike the banner type, which will dismiss itself, the alert waits for a response.  You can close the alert or open the app. Close the notification.

There is one user setting that all developers must be aware of. In the simulator go back to our apps notification settings. At the top you will find the Allow Notifications button.

Switch it off. All the other settings disappear.

Shut down the app in Xcode.  Build and run.  Set a 10 second Notification.  The system will let you do this but you will be waiting a long time for that notification –  it doesn’t exist.  The system shuts down our request for a notification.

In an app where notifications have major functionality, such as this timer app, we may want to tell the user that this is a bad idea.

We’d first have to know ourselves that notifications are off. We told the application which ones to turn on in the `AppDelegate`. There is a property that lets us look at those settings, `currentUserNotificationSettings`. It has a property `type`, which has a value of `UIUserNotification` type. This type uses a bitmask. If you’ve never used a bitmask before, it’s a way of compressing several `Bool` values into a single number. The three types we have each have one digit of a binary number. We thus can make an unsigned integer value from that value according to this table

Value `.Badge` (4) `.Sound`(2) `.Alert` (1)
0
(`.None`)
0 0 0
1 0 0 1
2 0 1 0
3 0 1 1
4 1 0 0
5 1 0 1
6 1 1 0
7 1 1 1

Notice the zero row. Remember we had four, not three options for `UIUserNotification`. The fourth option is` .None`. That is when all three of the others are off. When a user has notifications off in the user settings, the system always preempts our `currentUserNotificationSettings.type` setting it to `.None`. For an easy comparison, it often best to change this to a `rawValue` which gives us direct access to that integer value. Add this line under the one you just added:

`let noNotifications = UIUserNotificationType.None.rawValue`

This is just assigning a constant to the value 0, but for good documentation we write the longer way.
All this gets us to a simple `if`. If the user notifications is off, the type will be zero, otherwise it is on. Change the `setInterval` action to this:

```@IBAction func setInterval(sender: UIButton) {
//make a status string
let index = workoutType.selectedSegmentIndex
let workout = workoutType.titleForSegmentAtIndex(index)!
let status = displaySeconds() + " seconds " + workout
statusLabel.text = status + " set"

statusLabel.text = "Turn on notifications in settings"
} else{

}
```

We check if notifications are turned off. If off we send a message to the status label to tell the user the app doesn’t work. In a more sophisticated app I’d use an alert, explaining that the app doesn’t work without notifications, and include an action in the alert to take the user to the settings app.
Go back to the simulator, and make sure notifications are turned off.

Build and run.  Make a notification, and you get a message

While it give us the right message, It runs off the screen. Exit the app, and go to the storyboard. Select the status label.  In the attributes, change Lines to 0, Line Breaks to Word Wrap.

This sets the number of lines in the label to automatic.

Change the message to be a bit more verbose:

```statusLabel.text = "Please turn on notifications in Settings"
```

Build and run. When we try to set a notification, we get this:

Enable notifications in the settings app. Go back to the app and it works.

We may want to see all notifications currently waiting to fire.  There is an array `scheduledLocalNotifications` that lets us see this. We’ll set up a quick table view to display these. If you are not familiar with table views you might want to read this. Shut down the app in Xcode, and go to the storyboard.  Add a UIBarButtonItem to the right side of the navigation bar. Title it  List. Drag out a table view controller to the storyboard. Control drag from the List bar button to the view controller to get a segue. Make it a Show segue.

In the document outline, Select the Table View Cell

In the attributes inspector set the Identifier to cell and the Style to Basic.

We need to make the controller. I usually avoid the table view template. Press Command-N to make a new file.  Make a new Cocoa Touch Class file subclassing `UIViewController`.  Name the file NotificationsTableViewController. When the file appears, change the view controller to this:

```class NotificationsTableViewController: UITableViewController {

}
}
```

Go to the storyboard and select the table view controller. In the identity inspector, Change the class to NotificationsTableViewController.

Go to the NotificationsTableViewController class. Add two of the three data sources and a constant to the code like this:

```class NotificationsTableViewController: UITableViewController {

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

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
}

}
}
```

Our constant `notifications` contains an array of the scheduled notifications. We’ll use one section in the table, and our number of rows will be the number of scheduled notifications. Now add the last method we need to the class:

```override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
let row = indexPath.row
let dateString = NSDateFormatter.localizedStringFromDate(fireDate, dateStyle: .ShortStyle, timeStyle: .LongStyle)
cell.textLabel?.text = "Notification at " + dateString
if row % 2 == 0 {cell.backgroundColor = UIColor.lightGrayColor()}
return cell
}
```

This sets up each cell of the table. Since `notifications` is an array of `UILocalNotificaton`,s we go down the array getting the `fireDate` from the notification. We format the `fireDate` as a string and return it as a cell. I added a line to alternate the colors of the rows to make it slightly more readable.

You may need to delete notifications. We’ll delete any selected notification. Add the following code to the `NotificationsTableViewController` class.

```   override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let row = indexPath.row
}
```

To delete a notification, you use the `UIApplication` method `cancelLocalNotification`. We get that by `row`, cancel it, then refresh our notifications list and table. While I’m usually a bit careless about optionals to make the code easier to understand here’s one exception we need to be careful. Our table is not refreshing itself when a notification occurs. Between the time we look at the table and select a notification to delete, it may have already fired and dismissed itself. We check to make sure it is still there. Build and run. Add a few notifications and try deleting them.

There is one limitation to local notifications: you can only have 64 waiting to fire at one time. The most recent 64 will remain in the `scheduledLocalNotifications`, the rest are cancelled.

We’ve made an app that’s supposed to be a HIIT app. If you are not familiar with HIIT, it stands for High Intensity Interval Training. Usually for cardio training, you do a very intense exercise for a short amount of time then rest for a short amount of time to recover, then repeat several times. However, there’s a problem. If I do run/walk/run intervals for HIIT I might have over a hundred intervals. Other apps have nagging modes which remind you every minute or every hour to do something. Both of these would kill the 64 notification limit quickly.

We’ve used `scheduleLocalNotification` to schedule our notifications. If we don’t schedule them we don’t run up against the 64 notification limit. Instead we use `presentLocalNotificationNow` and let our code do the timing. We’ll use an `NStimer` to do this. If you are not familiar with `NSTimer` and the timing loop we will use, you might refer to my post on them

Go to the `ViewController` class. Add the following properties:

```var timer = NSTimer()
let timeInterval:NSTimeInterval = 10.0
var workout = false
var workoutIntervalCount = 5
```

The variable `timer` will be our timer with a firing time of every 15 seconds, which I set in a constant `timeInterval`. The code will alternate between working out and resting for a set number of intervals found in `workoutIntervalCount`. To set up the timer we’ll use this function:

```//MARK: -  NSTimer based notifications
func startTimer(){
if !timer.valid{ //prevent more than one timer on the thread
timer = NSTimer.scheduledTimerWithTimeInterval(
timeInterval,
target: self,
selector: #selector(timerDidEnd),
userInfo: nil,
repeats: true)
}
}
```

The timer will repeat every 15 seconds, executing the selector `timerDidEnd`. We now have to add that function:

```func timerDidEnd(timer:NSTimer){
if workoutIntervalCount == 0 { //finished intervals
timer.invalidate()
statusLabel.text = "Workout complete"
} else {
workout = !workout
if !workout {
statusLabel.text = String(format:"Interval %i Rest",workoutIntervalCount)
workoutIntervalCount -= 1
}else{
statusLabel.text = String(format:"Interval %i Work Out",workoutIntervalCount)
}

}
}```

This figures out which kind of notification we need to give, alternating between a workout and a rest. At each workout, we decrease `workoutIntervalCount`  by  one until we are at zero, where we shut off the timer. Under this code in the function `timerDidEnd` place the following to make our notification:

``` //make the local notification
}
```

Line 7 in this code uses `presentLocalNotificationNow` to immediately send the notification. Since this notification sends immediately, it ignores `fireDate` so we didn’t assign it this time. We did include line 5 however. Notifications are also badges, those little numbers on the corners of some icons, such as the one for mail. Using the property `applicationIconBadgeNumber`, We set it to the current workout interval count.
Instead of making a new button for this , we’ll run the code when `seconds = 0 `. Change `setInterval` to this:

```    @IBAction func setInterval(sender: UIButton) {
//make a status string
if seconds > 0 {
let index = workoutType.selectedSegmentIndex
let workout = workoutType.titleForSegmentAtIndex(index)!
let status = displaySeconds() + " seconds " + workout
statusLabel.text = status + " set"

} else{

}
}else{
workoutIntervalCount = 5
startTimer()
}

}

```

Now when we have a value of 0 for `seconds` our automatic interval counter will send notifications every 15 seconds. Build and run using the simulator. Tap the set interval button. Press Command-Shift-H and watch the results:

You’ll also notice the badge on the icon.

# Running on an iPhone: Using the Background

Up to this point we have been running this application on a simulator. You may get different results on an iPhone for the `NSTimer` based notifications. You may get nothing. Real devices suspend background operations unless you state otherwise. Fortunately, we can do that with a few more lines of code.
Add the highlighted line of code.

```//NSTimer executed functions
func startTimer(){
if !timer.valid{ //prevent more than one timer on the thread
timer = NSTimer.scheduledTimerWithTimeInterval(
timeInterval,
target: self,
selector: #selector(timerDidEnd),
userInfo: nil,
repeats: true)

}

}

```

The `beginBackgroundTaskWithExpirationHandler` method registers our code as a background task. iOS gives this background task an amount of time to finish. If it expires, the code in the closure runs. You can then gracefully shout down things. We’ll keep our app simple and leave the closure `nil`, which will end the app. This is only for simplicity. It is much better to write a handler.

The `beginBackgroundTaskWithExpirationHandler` method returns a unique ID as an `Int`. We’ll store this ID as a property of our class`backgroundTask`. At the top of our class, add this

` var backgroundTask = 0`

When our timer loop completes, we dismiss our app from the background. Add the highlighted line to `timerDidEnd`

```func timerDidEnd(timer:NSTimer){
//decrement the counter
if workoutIntervalCount == 0 { //finshed intervals
timer.invalidate()
statusLabel.text = "Workout complete"
```

With this code, you can build and run a a iPhone and get the same results as the simulator.

# Local Notifications and Apple WatchOS

If you have an Apple Watch and run this App on a phone, try running the app on your phone for the five intervals. Once started, put your phone to sleep by tapping the sleep switch. If your phone is asleep, your watch will display the notifications that were going to your phone.

Notifications to on the Apple Watch are completely free and automatic. No extra programming is required.

However, you may have noticed that notification in some apps give you haptics and sounds. Some notifications have extra buttons. These are controlled by more actions we can add to both iOS and WatchOS. In the next lesson,  we’ll look at how to make more buttons on your notification first in iOS and then in Watch OS.

# The Whole Code

## ViewController.swift

```//
//  ViewController.swift
//
//  Created by Steven Lipton on 4/20/16.
//

import UIKit

class ViewController: UIViewController {
//MARK: Properties
var seconds:NSTimeInterval = 0.0
//MARK: - Outlets
@IBOutlet weak var statusLabel: UILabel!
@IBOutlet weak var workoutType: UISegmentedControl!
@IBOutlet weak var secondsIndicator: UILabel!

//MARK: - Actions
@IBAction func upArrow(sender: UIButton) {
seconds += 1.0
secondsIndicator.text = displaySeconds()

}
@IBAction func downArrow(sender: UIButton) {
seconds -= 1
if seconds < 0{ seconds = 0.0 } secondsIndicator.text = displaySeconds() } @IBAction func setInterval(sender: UIButton) { //make a status string if seconds > 0 {
let index = workoutType.selectedSegmentIndex
let workout = workoutType.titleForSegmentAtIndex(index)!
let status = displaySeconds() + " seconds " + workout
statusLabel.text = status + " set"

} else{

}
}else{
workoutIntervalCount = 5
startTimer()
}

}
//MARK: - Instance Methods
func displaySeconds() -> String{
let mySeconds = String(format:"%02i",Int(seconds))
return mySeconds
}

var timer = NSTimer()
let timeInterval:NSTimeInterval = 5.0
var workout = false
var workoutIntervalCount = 5

//NSTimer executed functions
func startTimer(){
if !timer.valid{ //prevent more than one timer on the thread
timer = NSTimer.scheduledTimerWithTimeInterval(
timeInterval,
target: self,
selector: #selector(timerDidEnd),
userInfo: nil,
repeats: true)

}

}

func timerDidEnd(timer:NSTimer){
//decrement the counter
if workoutIntervalCount == 0 { //finshed intervals
timer.invalidate()
statusLabel.text = "Workout complete"
} else {
workout = !workout
if !workout {
statusLabel.text = String(format:"Interval %i Rest",workoutIntervalCount)
workoutIntervalCount -= 1
}else{
statusLabel.text = String(format:"Interval %i Work Out",workoutIntervalCount)

}

}

}
//MARK: - Life Cycle

}

}

```

## AppDelegate.swift

```//
//  AppDelegate.swift
//
//  Created by Steven Lipton on 4/20/16.
//

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?

//methods not overridden not included.
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
categories: nil
)
)
return true
}
}
```

```//
//
//  Created by Steven Lipton on 4/22/16.
//

import UIKit

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

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
}

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("cell", forIndexPath: indexPath)
let row = indexPath.row
let dateString = NSDateFormatter.localizedStringFromDate(fireDate, dateStyle: .ShortStyle, timeStyle: .LongStyle)
cell.textLabel?.text = "Notification at " + dateString
if row % 2 == 0 {cell.backgroundColor = UIColor.lightGrayColor()}
return cell
}

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
let row = indexPath.row
}

}

}

}

```

# The Step by Step Guide to Custom Presentation Controllers

Ever wanted that sliding sidebar or an alert with a image picker? Apple has many great ways of presenting view controllers,  but sometimes we want something different, something new. For that we subclass `UIPresentationController`. However there’s a few concepts that you’ll need to wrap your head around first. In this lesson we’ll create a few standard controllers to explain the custom controllers, then make and animate our own custom controller sliding  side bar. We’ll build the presentation controller step by step, so you know how it really works.

# Custom Presentation Anatomy in Alert Views.

Make a new project called SwiftCustomPresentation, with a universal device and Swift as the language.  Once loaded go to the launchscreen.storyboard. I like to have some indication that things are working, and since Apple removed the default launch screen layout, I tend to add my own. Set the background color to Yellow(#FFFF00). Drag a label on the launch screen  and title it Hello in 26 point size.  Click the alignment auto layout button at the bottom of the storyboard and check on Horizontally in Container and Vertically in Container set to 0. Update the frames for  Items  of  new constraints, then click Add 2 constraints.

You now have a nice label in the center of the launch screen

Go to the storyboard. Make the background Yellow(#FFFF00). Drag a button to the center of the storyboard. Title the label Hello, Pizza as a 26 point size system font. Make the text color Dark Blue(#0000AA) Just like the label on the launch screen, align the button to the center of the storyboard.  Click the alignment auto layout button at the bottom of the storyboard and check on Horizontally in Container and Vertically in Container set to 0. Update the frames for  Items  of  new constraints, then click Add 2 constraints.

Open the assistant editor. Control drag from the button to the code. Create an action entitled `showAlert`. Close the assistant editor for now. Ooen the ViewController.swift file.  Change the action to this:

```@IBAction func showAlert(sender: UIButton){
}
```

```func helloAlert(){
title: "Hello Slice",
title: "Okay",
style: .Default,
handler: nil)
animated: true,
completion: nil)
}
```

This is  code to present the simplest alert possible.  We create a simple alert and give it one action, an Okay button that dismisses the alert. The last line is the important one for our discussion:

```
animated: true,
completion: nil)
```

As of iOS8, all modal view controllers present with this one method.  You tell the method which controller you want to present, set a few properties on it and it does the work, no matter what your device. It relieves a lot of the hard work of developers specifying exceptions for individual devices.

Set your simulator for an iPhone 6s. Build and run.  When the Hello pizza button shows in the simulator, tap it. You get your alert.

We’ve made this alert to illustrate the three parts you need to know about any custom view controller.

Our yellow background is the presenting view controller, the controller that calls the `presentViewController `method The alert, which is the presented view controller, is the controller `presentViewController` uses in its parameters.

`presentingViewController.presentViewController(presentedViewController, animated:true,completion:nil)`

In an alert and in other view controllers such as popovers, the `presentViewController` method adds a special view  between the presented and presenting view controllers called a chrome. The chrome is the difference or padding between the bounds of the presented controller, and the bounds of the presenting controller. Usually it is a solid color with some alpha value. Apple tends to use a gray color for chrome, which is why yellow is looking like a dark orange yellow.

Alerts help us explain the anatomy of a presentation controller. However they are rather automatic in their execution. Let’s add a simple modal view controller to play with custom view controllers.  Press Command-N and select a new Cocoa Touch Class ModalViewController. Do check on Also Create XIB file. This is one of those places I prefer xibs due to portability over the storyboard.

Save the file. Go to  the ModalViewController.xib file. Change the background to Dark Blue(#0000AA). Add two labels to the xib. In one make the text Ready for your slice? , a Font of 26.0 Bold, and White(#FFFFFF) text. Set the Alignment to Left justified. Set the  Lines  property to 0 and the Line Breaks  to Word Wrap. This will let the label vary the number of lines to fit the text, and word wrap the results. Your attributes should look like this:

For the second label, add a short paragraph. I used a passage from Episode 4 of my podcast A Slice of App Pie.

This is the other thing about persistence: It does not see success as an absolute. It is not a Bool, a true/false variable, but a Double,  a real number. It is not just black or white, but every color.  You are not a success, but you are at a degree of success. Your past experience fuels your future success.

Set the  Font to 16.0 Regular, and White(#FFFFFF) text. Set the Alignment to Full  Justified. Set the  Lines  property to 0 and the Line Breaks  to Word Wrap.

Select the text paragraph and Control drag  down and to the right until you are over the blue of the background.

Release the mouse button and you will see an auto layout menu. Hold down shift and Select  Trailing Space to Container, Bottom Space to Container and Equal Widths:

Click the Add Constraints button. Now control-drag from the Ready label to the paragraph label.  In the auto layout menu that appears, Shift-Select Vertical Spacing, Trailing, and Equal Widths

Click the Add Constraints button. Select the paragraph and go to  the size inspector .  You’ll see a list of constraints:

Your values will most likely be different than the illustration. Click the edit button for the Trailing Space to: Superview. A popup appears. Change the Constant to 8.

Click the Equal Width: to Superview edit button. Change the Multiplier to 0.9.

Edit the Bottom Space to: Superview constraint. Change the Constant to 20.

Edit the Align Trailing Space to: Ready for yo… constraint. Change the Constant to 0.

Edit the Top Space to: Ready for yo… constraint. Change the Constant to 20.

Edit the Equal Width to: Ready for yo… constraint. Change the Multiplier to 0.5.

If you’ve never worked with auto Layout before, what we just did is anchor the bottom right corner of the paragraph to the bottom right corner of the xib. with a margin of 20 points on the bottom and 8 points on the right. We set the width of the paragraph to 90% of the width of the xib. The Label above it, acting as a title, we made half as long as the paragraph, and aligned to the right side of the paragraph, 20 points up.

Click  the triangle tie fighter which is the auto layout  resolve button. You get a menu like this:

Select for the All Views in View section Update Frames. You now have a layout like this:

We’ll dismiss this modal with a swipe to the right. In the object library,  find the swipe gesture:

Drag it to the blue of the xib and release. Nothing will happen there but in the document outline (if you don’t have it open click the  button)  you will see a new object listed

Select the Swipe Gesture Recognizer and in the attributes menu, you should see the following:

These are the defaults and what we want: a single finger swipe to the right.  Open the assistant editor and control-drag the Swipe Gesture Recognizer from the document outline to the code. Create an action named dismissModal.

In the code that appears, dismiss the vew controller:

```@IBAction func dismissModal(sender: AnyObject) {
dismissViewControllerAnimated(true, completion: nil)
}```

## Presenting the View Controller.

Go back to the ViewController.swift File.  Add the following method:

``` func presentModal() {
let helloVC = ModalViewController(
nibName: "ModalViewController",
bundle: nil)
helloVC.modalTransitionStyle = .CoverVertical
presentViewController(helloVC,
animated: true,
completion: nil)
}```

The code gets the view controller  and the xib then presents it. We’re using the default settings for a modal in this case.

Go to the storyboard.  Open the assistant editor if not already open. Drag a Swipe Gesture recognizer to the storyboard. Select it in the the document outline and change the Swipe attribute  to Up. Control-drag from the Swipe Gesture recognizer and make an outlet

```@IBAction func swipeUp(
sender: UISwipeGestureRecognizer) {
presentModal()
}
```

Build and run.You should be able to swipe up and show the blue controller.

The title is too small to fit on one line and adapts to two. Rotate the phone (in the simulator press Command right-arrow) and you get a slightly different layout:

Swipe right and the view dismisses

# Custom Presentation #1: A  Big Alert View

We’ve got a working modal view controller. We did this for several reasons. This proves there’s no magic in what we are about to do. It also reinforces how we do this in a standard presentation controller.

## Adding the Custom Presentation Controller

Create a new class by pressing Command-N on the key board in Xcode. Make a new cocoa touch class MyCustomPresentationController subclassing `UIPresentationController`.  You end up with an empty class:

```class MyCustomPresentationController: UIPresentationController {
}```

```let chrome = UIView()
let chromeColor = UIColor(
red:0.0,
green:0.0,
blue:0.8,
alpha: 0.4)```

A presentation controller needs to do three things: Start the presentation, end the presentation and size the presentation. The `UIPresentationController` class has three methods we override to do this: `presentationTransitionWillBegin`, `dismissalTransitionWillBegin` and `frameOfPresentedViewInContainerView`. There is a fourth method `containerViewWillLayoutSubviews` which may sound familiar to those who have worked with code and auto layout. When there is a change to the layout, usually rotation, this last method will make sure we resize everything.

First we present the controller. In our code we control what the chrome does. To our custom presentation controller, add the following method

```override func presentationTransitionWillBegin() {
chrome.frame = containerView!.bounds
chrome.alpha = 1.0
chrome.backgroundColor = chromeColor
containerView!.insertSubview(chrome, atIndex: 0)
}```

First we set the size of the chrome by the size of `containerView`. The `containerView` property is a view which is an ancestor of the presenting view in the view hierarchy. `containerView` gives us a view that is bigger to or the same size as the presenting view. Setting the chrome to this size means the chrome will cover everything. We then set the color and alpha of `chrome`, and then add `chrome` to the container view.

Our next method to implement is `dismissalTransitionWillBegin.` We’ll remove the chrome from the view hierarchy here. Add this code:

``` override func dismissalTransitionWillBegin() {
self.chrome.removeFromSuperview()
}
```

We’ll change the size of the presented view so we can see the chrome. Size changes take two methods. The first is `frameOfPresentedViewInContainerView`. Add the following code:

```override func frameOfPresentedViewInContainerView() -> CGRect {
return containerView!.bounds.insetBy(dx: 30, dy: 30)
}```

This returns the frame of the container. We used the `insetBy` function to shrink it 30 points within the container view. This will give us a effect similar to an alert.

To make sure adaptive layout changes everything, we need one more method. add this:

```override func containerViewWillLayoutSubviews() {
chrome.frame = containerView!.bounds
presentedView()!.frame = frameOfPresentedViewInContainerView()
}
```

Our first line changes the chrome’s size to fit the new size of the view. The second one makes sure that the presented view is the correct size by calling the method we just wrote `frameOfPresentedViewInContainerView`.

Custom presentation controllers run through a delegate. Above the `MyCustomPresentationController` class, add the following:

```class MyTransitioningDelegate : NSObject, UIViewControllerTransitioningDelegate {
func presentationControllerForPresentedViewController(
presented: UIViewController,
presentingViewController presenting: UIViewController,
sourceViewController source: UIViewController
) -> UIPresentationController? {
return MyCustomPresentationController(
presentedViewController: presented,
presentingViewController: presenting)
}
}```

This is a subclass of the `UIViewControllerTransitioningDelegate`. Though the parameters are long, the single function in the delegate returns our presentation controller, using the designated initializer for the class.

That is all we need for a bare bones custom controller. Our next step is to use it.

## Using the Custom Presentation Controller

We’ll add a left swipe gesture for presentation this controller. Go to the storyboard. Drag a swipe gesture control on the view. Set the Swipe attribute this time for Left. Open the assistant editor and control-drag this gesture to the `ViewController` class, making a new action swipeLeft. Change the new function to this:

```@IBAction func swipeLeft(sender: UISwipeGestureRecognizer) {
presentCustomModal()
}```

Close the assistant editor and go to the ViewController.swift code. Add the following to the `ViewController` class, under to the `presentModal` function so you can compare the two

```func presentCustomModal(){
let helloVC = ModalViewController(
nibName: "ModalViewController",
bundle: nil)
helloVC.transitioningDelegate = myTransitioningDelegate
helloVC.modalPresentationStyle = .Custom
helloVC.modalTransitionStyle = .CrossDissolve
presentViewController(helloVC,
animated: true,
completion: nil)
}```

Like the standard modal controller, we get the controller and present it. We did change the transition style to tell the difference between the two controllers, and as you’ll see a cross dissolve makes a better transition for this type of view.

Unlike `presentModal`, we set the `modalPresentationStyle` to `.Custom` so `presentViewController` knows to look for a custom presentation controller. However it won’t work without setting the view controller’s `transitioningDelegate` property. The transitioning delegate tells the view controller where the custom transition is. If this is `nil`, the presentation is a standard presentation, not a custom one.

We haven’t set the delegate yet. At the top of the `ViewController` class, add this line:

`let  myTransitioningDelegate = MyTransitioningDelegate()`

Build and Run. Once Hello,Pizza appears, swipe left and the modal view appears with chrome around it.

Rotate the device .

Swipe right and the view disappears

# Why Apple Uses Gray Chrome

You’ll notice that the chrome does not turn blue, but instead tuns green. As a transparent color, it blends with the color under it, sometimes not in the most attractive way. This is why Apple uses gray for chrome — you never have the problem with gray. If we change the chrome’s `backgroundColor` like this:

```//let chromeColor = UIColor(red:0.0,green:0.0,blue:0.8,alpha: 0.4) //mixes with background colors
let chromeColor = UIColor(white: 0.5, alpha: 0.6) //gray dims the background
```

Then build and run. We get a  slightly different effect:

You’ll notice in both these cases however, the presented controller seems to glow. This is not because of code, but a trick of your brain called Simultaneous contrast . The brain has a hard time dealing with two hues that are complements next to each other, so it starts to make things up to compensate. I used two colors most likely to do this to each other, blue and yellow. There are two strategy you can use to prevent this. One is use less jarring colors in your color scheme for your app. The second is to change the chrome to have a high alpha value and not be as transparent. Change the code to this:

```//let chromeColor = UIColor(red:0.0,green:0.0,blue:0.8,alpha: 0.4) //mixes with background colors
//let chromeColor = UIColor(white: 0.4, alpha: 0.6) //gray dims the background
let chromeColor = UIColor(red:0.0,green:0.0,blue:0.8,alpha: 0.7) // not as transparent```

The chrome is very blue, and the effect is far less.

Set the chrome back to the gray for the rest of the tutorial.

# Animating the Chrome

You’ll notice that the chrome appears and disappears rather abruptly. We need to add some animation to the chrome so it transitions smoothly. There is  an object called a transition coordinator that automatically loads into the view controller during presentation. It gives you a way to do animation parallel to the main animation.  There’s a method in the transition coordinator `animateAlongTransition:completion:` that we’ll use to fade the chrome as the presented controller fades in.

In the `MyCustomPresentationController` class, change the method to this

```override func presentationTransitionWillBegin() {
chrome.frame = containerView!.bounds
//chrome.alpha = 1.0
chrome.backgroundColor = chromeColor
containerView!.insertSubview(chrome, atIndex: 0)
presentedViewController.transitionCoordinator()!.animateAlongsideTransition(
{context in
self.chrome.alpha = 1.0
},
completion: nil)
}```

We changed to code to start the chrome with an `alpha` of 0. The `transitionCoordinator` function returns the transition coordinator as an optional value. We use its `animateAlongsideTransition` method to transition for the invisible chrome to a visible one.

In the `presentationTransitionWillBegin`, we do nothing in the completion closure of `animateAlongsideTransition`. On the other hand, we’ll remove the chrome in the `dismissalTransitionWillBegin`. Add this code.

```override func dismissalTransitionWillBegin() {
presentedViewController.transitionCoordinator()!.animateAlongsideTransition(
{ context in
self.chrome.alpha = 0.0
},
completion: {context in
self.chrome.removeFromSuperview()
}
)
//self.chrome.alpha = 0.0
//self.chrome.removeFromSuperview()
}```

We fade out the chrome, and once the chrome completely fades at the end of the main animation, we remove the view.

With those changes, build and run. The chrome fades in and out smoothly

# Custom Presentation #2: A Sidebar

A comma use for a custom presentation controller is a toolbar or side bar. Let’s modify the code to make a sidebar on the right side of our device.

## Changing the frame

For a side bar we are setting the view on one side of the `contentView` instead of the center as we do with `insetBy`. Change `frameOfPresentedViewInContainerView` to

```override func frameOfPresentedViewInContainerView() -> CGRect {
//return containerView!.bounds.insetBy(dx: 30, dy: 30)  //center the presented view
let newBounds = containerView!.bounds
let newWidth:CGFloat = newBounds.width / 3.0 // 1/3 width of view for bar
let newXOrigin = newBounds.width - newWidth //set the origin from the right side
return CGRect(x: newXOrigin, y: newBounds.origin.y, width: newWidth, height: newBounds.height)
}
```

We commented out the `insetBy`, and took control of the frame directly. We take the size of the container view, and divide by three to make a frame size  a third the width of the container. We also set the origin to one-third less the width of the container view to make the bar on the right. Build and run. It’s there, but portrait does not look so good.

Landscape looks a lot better, since it has more space

We can change the proportions to fit better. We’ll make it 3/4 of the width. Change the code to this:

`var newWidth:CGFloat = newBounds.width * 0.75 // 3/4 width of view for bar`

This will work, but will be way too big on an iPad or iPhone 6 plus in landscape. We can use a trait collection to reduce the size to one third on the bigger devices. add this to the code, just under the `newWidth` declaration:

```if containerView!.traitCollection.horizontalSizeClass == .Regular{
newWidth = newBounds.width / 3.0 //1/3 view on regular width
}```

Change your simulator to an iPhone 6s plus. Build and run. In  portrait, we get a 3/4 view

In landscape, with the regular width size class, we get a  1/3.

Change to an iPad Air 2 simulator. We get 1/3 on both landscape and portrait.

# Animating the Side Bar

Side bars look best when they transition by sliding in. While we can animate the chrome with `animateAlonsideTransition`, we cannot do so for the frame of the presented controller. To do that we need to use another class,  `UIViewControllerAnimatedTransitioning`.

While making a new class is probably a better way of doing this, I’m going to keep it  together with the presentation controller.  Just under  the `import UIKit` in `MyCustomPresentationController.swift,` add the following:

```class MyAnimationController: NSObject,UIViewControllerAnimatedTransitioning{
var isPresenting :Bool
let duration :NSTimeInterval = 0.5
}
```

The  `UIViewControllerAnimatedTransitioning`  protocol contains a series of functions to create an animation for both dismissal and presentation.  It has two required functions, where we use these two properties.

We added two properties to our class. `isPresenting` will be our indicator if this is a dismissal or presentation. To make it easier to use, add this to the class:

```init(isPresenting: Bool) {
self.isPresenting = isPresenting
super.init()
}```

This will set the value when we initialize the class. We’ll use it in a required method `animateTransition`. This method tells the system what to do when there is a transition. We’ll set it up to do both a presentation animation and a dismissal. Add this code:

```func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
if isPresenting {
animatePresentationTransition(transitionContext)
} else {
animateDismissalTransition(transitionContext)
}
}```

The parameter `transitionContext` type `UIViewControllerContextTransitioning` contains all the information you need to do the animation transition, including the presented and presenting controllers and the container view. We’ll pass those on to two more functions we’ll write shortly to animate presentation and dismissal of the presenting view controller.

Our other property, `duration` will set the time for the animation duration in the other required function. Add this code:

``` func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
return duration
}
```

This satisfies the two required functions for the protocol. We are still getting errors for out two animation functions though. Add these to the class:

```func animatePresentationTransition(transitionContext: UIViewControllerContextTransitioning){
}
func animateDismissalTransition(transitionContext: UIViewControllerContextTransitioning){
}```

Our first step is to add a presentation animation in `animatePresentationTransition`. We animate using one of the UIView animation class methods `animateWithDuration`. There are different version for different effects, whihc you can read more about in the UIView Class Refrence. All of these will use closures to describe the end state of the animation. We set the presenting view controller to a state where we will star the animation, then in the animation block give its final state. The `animateWithDuration` does the rest.

To present the controller’s animation, we’ll need a few thing from the the transition context. Add this to the code for `animatePresentationTransition`

```        // Get everything you need
let presentingViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!
let finalFrameForVC = transitionContext.finalFrameForViewController(presentingViewController)
let containerView = transitionContext.containerView()
let bounds = UIScreen.mainScreen().bounds
```

We get the `presetingviewController` to be able to set its state before and after animation. We also get the container view for adding the presenting view controller. The `finalFrameForVC` is the `CGFrame` that will be the end of the animation. We’ll use bounds to give us the bounds of the visible screen.

The next step is to change the frame of the presenting view controller to where it should be before the animation begins. we want it off to the right side of the visible view. Since we are not moving anything in the Y direction, we want to have our starting point as the width of the visible view. Add this code:

```        //move our presenting controller to the correct place, and add it to the view
presentingViewController.view.frame = CGRectOffset(finalFrameForVC, bounds.size.width, 0)
presentingViewController.view.alpha = 0.0
```

Besides the presenting view moving off of stage right, I also dimmed the view to an `alpha` of 0.0. I then added the view to the container view. The next step is the big one — add the animation with this code:

```//animate the transition
UIView.animateWithDuration(
transitionDuration(transitionContext), //set above
delay: 0.0,
options: .CurveEaseOut, //Animation options
animations: { //code for animation in closure
presentingViewController.view.frame = finalFrameForVC
presentingViewController.view.alpha = 1.0
},
completion: { finished in  //completion handler closure
transitionContext.completeTransition(true)
}
)```

There’s a lot of unpack in this method’s parameters. We start with a duration we get from the `transitionDuration` method we defined earlier. Next thre is a delay to begin the animation, which we leave at ). The next parameter `options` takes a value from `UIViewAnimationOptions` to describe the behavior of the animation.

The next parameter, animations, describes the final state of the animation. In our code it sets the view controller’s frame to the final frame fro the presentation, and sets the `alpha` to 1.

Once the animation is complete there is a completion handler, where we set in the transition context a flag that says we are done animating.

For a dismissal, we do the same in reverse.Add this to `animateDismissalTransition`:

```
let presentedControllerView = transitionContext.viewForKey(UITransitionContextFromViewKey)
let containerView = transitionContext.containerView()
```

We first get our presented controller view and the container view. This time, the current position of the frame is the position we start from, so there is no setting the initial frame of the animation. Instead we got straight into the animation, which animates the presented controller view to the edge of the container view. Add the animation:

```        // Animate the presented view off the side
UIView.animateWithDuration(
transitionDuration(transitionContext),
delay: 0.0,
options: .CurveEaseIn,
animations: {
presentedControllerView!.frame.origin.x += containerView!.frame.width
presentedControllerView!.alpha = 0.0
},
completion: {(completed: Bool) -> Void in
transitionContext.completeTransition(completed)
}
)
```

## Add the Animations to the Delegate

The `UIViewControllerTransitioningDelegate` does more than just hold the custom transition controller. It has optional methods for animation. Add to `MyTransitioningDelegate` the following

```func animationControllerForPresentedController(
presented: UIViewController,
presentingController presenting: UIViewController,
sourceController source: UIViewController
) -> UIViewControllerAnimatedTransitioning? {
return MyAnimationController(isPresenting:true)
}
```

After a long list of parameters, we return a `MyAnimationController` with `isPresenting` set to true. We set to false for a dismissal in this function

```func animationControllerForDismissedController(
dismissed: UIViewController
) -> UIViewControllerAnimatedTransitioning? {
return MyAnimationController(isPresenting:false)
}
```

Build and run. We now have an animated custom transition

# More Things to Try.

This rather long tutorial just breaks the ice in what you can do with a custom presentation. You do not have to use a xib, for example, Storyboards works just as well, with either segues or storyboard id’s plus a reference to the delegate. There are many more animation options as well.

Also a word of caution. I intentionally used a lot of optional values as explicit values to keep things simple and readable. You might not want to be as careless as I am here, and check for `nil` or optional chain much more often than I did in this code.

# The Whole Code

## ViewController.swift

```//
//  ViewController.swift
//  SwiftCustomPresentation
//
//  Created by Steven Lipton on 4/7/16.
//

import UIKit

class ViewController: UIViewController, UIViewControllerTransitioningDelegate {
let  myTransitioningDelegate = MyTransitioningDelegate()

//MARK: Actions
}
@IBAction func swipeLeft(sender: UISwipeGestureRecognizer) {
presentCustomModal()
}

@IBAction func swipeUp(sender: UISwipeGestureRecognizer) {
presentModal()
}
//MARK: Instance methods
title: "Hello Slice",
title: "Okay",
style: .Default,
handler: nil)
animated: true,
completion: nil)
}

func presentModal() {
let helloVC = ModalViewController(nibName: "ModalViewController", bundle: nil)
helloVC.modalTransitionStyle = .CoverVertical
presentViewController(helloVC, animated: true, completion: nil)
}

func presentCustomModal(){
let helloVC = ModalViewController(nibName: "ModalViewController", bundle: nil)
helloVC.transitioningDelegate = myTransitioningDelegate
helloVC.modalPresentationStyle = .Custom
helloVC.modalTransitionStyle = .CrossDissolve
presentViewController(helloVC, animated: true, completion: nil)
}

//MARK: Life Cycle
}

// Dispose of any resources that can be recreated.
}

}

```

## MyCustomPresentationController.swift

```//
//  MyCustomPresentationController.swift
//  SwiftCustomPresentation
//
//  Created by Steven Lipton on 4/7/16.
//

import UIKit

class MyAnimationController: NSObject,UIViewControllerAnimatedTransitioning{

var isPresenting :Bool
let duration :NSTimeInterval = 0.75

init(isPresenting: Bool) {
self.isPresenting = isPresenting
super.init()
}

func transitionDuration(transitionContext: UIViewControllerContextTransitioning?) -> NSTimeInterval {
return duration
}

func animateTransition(transitionContext: UIViewControllerContextTransitioning) {
if isPresenting {
animatePresentationTransition(transitionContext)
} else {
animateDismissalTransition(transitionContext)
}
}

func animatePresentationTransition(transitionContext: UIViewControllerContextTransitioning){
// Get everything you need
let presentingViewController = transitionContext.viewControllerForKey(UITransitionContextToViewControllerKey)!
let finalFrameForVC = transitionContext.finalFrameForViewController(presentingViewController)
let containerView = transitionContext.containerView()
let bounds = UIScreen.mainScreen().bounds

//move our presenting controller to the correct place, and add it to the view
presentingViewController.view.frame = CGRectOffset(finalFrameForVC, bounds.size.width, 0)
presentingViewController.view.alpha = 0.0

//animate the transition
UIView.animateWithDuration(
transitionDuration(transitionContext), //set above
delay: 0.0,
options: .CurveEaseOut, //Animation options
animations: { //code for animation in closure
presentingViewController.view.frame = finalFrameForVC
presentingViewController.view.alpha = 1.0
},
completion: { finished in  //completion handler closure
transitionContext.completeTransition(true)
}
)
}

func animateDismissalTransition(transitionContext: UIViewControllerContextTransitioning){

let presentedControllerView = transitionContext.viewForKey(UITransitionContextFromViewKey)
let containerView = transitionContext.containerView()

// Animate the presented view off the side
UIView.animateWithDuration(
transitionDuration(transitionContext),
delay: 0.0,
options: .CurveEaseInOut,
animations: {
presentedControllerView!.frame.origin.x += containerView!.frame.width
presentedControllerView!.alpha = 0.0
},
completion: {(completed: Bool) -> Void in
transitionContext.completeTransition(completed)
}
)
}
}

class MyTransitioningDelegate : NSObject, UIViewControllerTransitioningDelegate {
func presentationControllerForPresentedViewController(
presented: UIViewController,
presentingViewController presenting: UIViewController,
sourceViewController source: UIViewController
) -> UIPresentationController? {
return MyCustomPresentationController(
presentedViewController: presented,
presentingViewController: presenting)
}
func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return MyAnimationController(isPresenting:true)
}
func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return MyAnimationController(isPresenting:false)
}
}

class MyCustomPresentationController: UIPresentationController {
let chrome = UIView()
//let chromeColor = UIColor(red:0.0,green:0.0,blue:0.8,alpha: 0.4) //mixes with background colors
let chromeColor = UIColor(white: 0.4, alpha: 0.6) //gray dims the background
//let chromeColor = UIColor(red:0.0,green:0.0,blue:0.8,alpha: 0.7) // not as transparent

override func presentationTransitionWillBegin() {
chrome.frame = containerView!.bounds
chrome.alpha = 0.0
//chrome.alpha = 1.0
chrome.backgroundColor = chromeColor
containerView!.insertSubview(chrome, atIndex: 0)
var newframe = frameOfPresentedViewInContainerView()
newframe.origin.x = newframe.width
presentedViewController.view.frame = newframe
presentedViewController.transitionCoordinator()!.animateAlongsideTransition(
{ context in
self.chrome.alpha = 1.0
self.presentedViewController.view.frame = self.frameOfPresentedViewInContainerView()
},
completion: nil)
}

override func dismissalTransitionWillBegin() {
presentedViewController.transitionCoordinator()!.animateAlongsideTransition(
{ context in

self.chrome.alpha = 0.0
},
completion: {context in
self.chrome.removeFromSuperview()
}
)
//self.chrome.alpha = 0.0
//self.chrome.removeFromSuperview()
}

override func frameOfPresentedViewInContainerView() -> CGRect {
//return containerView!.bounds.insetBy(dx: 30, dy: 30)
let newBounds = containerView!.bounds
var newWidth:CGFloat = newBounds.width * 0.75 // 3/4 width of view for bar
//var newWidth:CGFloat = newBounds.width / 3.0 // 1/3 width of view for bar
if containerView!.traitCollection.horizontalSizeClass == .Regular{
newWidth = newBounds.width / 3.0 //1/3 view on regular width
}
let newXOrigin = newBounds.width - newWidth //set the origin 1/3 from the right side
return CGRect(x: newXOrigin, y: newBounds.origin.y, width: newWidth, height: newBounds.height)
}

/*
if containerView!.traitCollection.horizontalSizeClass == .Regular {
newWidth = newBounds.width * 0.33
} else { //compact and unknown 80%
newWidth = newBounds.width * 0.8
}
*/
override func containerViewWillLayoutSubviews() {
chrome.frame = containerView!.bounds
presentedView()!.frame = frameOfPresentedViewInContainerView()
}
}
```

## ModalViewController.swift

```//
//  ModalViewController.swift
//  SwiftCustomPresentation
//
//  Created by Steven Lipton on 4/7/16.