How I Used Swift to Build a Map Based Location Tracker for iOS

Anything location based is really cool, and having that information displayed on a map is even better! So … lets track our location and plot it on a map :)

The good news about this tutorial is there is very little code! The flip side is, we will have to do some extra setup. Lets begin!

Preface: I’m still very much a beginner to Swift, and I am just sharing my journey to help out other beginners :) I’m also using Xcode beta 5 for this.

Setup

Setting up the project

File -> New -> Project

Then select

iOS -> Application -> Single View Application

Give it a name and make sure we are using the language Swift :)



Open our Main.storyboard file.



Show the document outline. There is a little handle in the lower left window of the storyboard to do this.

Highlight our View Controller for this scene, and navigate to the attributes inspector.

For this project, we are going to set the size to be “Retina 4-Inch Full Screen” and I’m going to set the Orientation to Portrait.

Setting up the MapKit View

Apple has already provided us with a map view. So we just need to drag one into our scene.



Setting up the label

We are also going to have a label to display some debug information about our location. Drag one into the scene as well.



Feel free to adjust the attributes in the inspector to make the label look like mine. I centered the text, gave the label 3 lines, and used the awesomely cool font ‘Helvetica Neue Thin’ with a font size of 12 (incorrectly “17.0” in screen shot).

Creating the IBOutlets

Now that we have our mapview and label, we are going to drag them into our ViewController.swift code so we can control them with code.

We want to switch to assistant editor (the view that looks like a suit and bow tie in the upper right), and then “right click drag” our MKMapView into our ViewController.swift file.





We also want to right click, and drag from the Label to our ViewController.swift file.





You will see some errors, but this will go away once we fix our imports. If you are dying to fix this now, add this under import UIKit

import CoreLocation import MapKit

Editing the info.plist

We need to add 2 keys to our info.plist file, which is located in the “Supporting Files” folder. The two keys are NSLocationWhenInUseUsageDescription and NSLocationAlwaysUsageDescription . Right click on “Information Property List”, click Add Row , and manually enter these two keys.

The final form should look like this:

Simulating your location

The last thing I want to mention is there is no way (I saw) to have the iOS simulator aware of your actual location. However, the simulator DOES allow you to fake this data. Make sure you have a good simulation selected or else this program will just show an empty map.

Once you have the simulator going select a location!!!



ViewController.swift and Full Code

Phew! Thank goodness all that setup is out of the way. Time for the code!

Inheritance & Initial variables

class ViewController : UIViewController, CLLocationManagerDelegate, MKMapViewDelegate {

CCLocationManagerDelegate

MKMapViewDelegate

If you feel comfortable with the concept of inheritance, try holding the command key and clicking on MKMapViewDelegate or CCLocationManagerDelegate to get a list of methods that we can use.

If you are not comfortable, its not that important for this tutorial.

@IBOutlet weak var theMap : MKMapView ! @IBOutlet weak var theLabel : UILabel ! var manager :CLLocationManager ! var myLocations : [CLLocation] = []

We create a manager of type CLLocationManger and since we are not giving it an initial value, we make it an optional with the ! mark.

Per Apple’s definition: “Optionals say either “there is a value, and it equals x” or “there isn’t a value at all”. Optionals are similar to using nil with pointers in Objective-C, but they work for any type, not just classes. Optionals are safer and more expressive than nil pointers in Objective-C and are at the heart of many of Swift’s most powerful features.”

We also set up an array of CLLocation ’s and name that myLocations . This is where we are going to store every location we go to. I initialize it as an empty array, so no need for an optional here :)

viewDidLoad

For the sake of this app, this functions acts as our entry point to the entire program. Technically, this function is called when the view is done loading.

override func viewDidLoad () { super .viewDidLoad() //Setup our Location Manager manager = CLLocationManager() manager.delegate = self manager.desiredAccuracy = kCLLocationAccuracyBest manager.requestAlwaysAuthorization() manager.startUpdatingLocation()

CLLocationManager

locationManager(manager:CLLocationManager, didUpdateLocations locations:[AnyObject])

There are various desiredAccuracy’s we can use, but we want this accurate to within 5 meters, so we are using kCLLocationAccuracyBest .

When we call manager.requestAlwaysAuthorization you will get a little popup on your iOS device that will ask for permission so that the app will know our location. I encourage you to say yes to this ;)

Finally, we call manager.startUpdatingLocation() which actually starts checking if we change locations or not. If we change locations, it will call:

locationManager(manager:CLLocationManager, didUpdateLocations locations:[AnyObject])

//Setup our Map View theMap.delegate = self theMap.mapType = MKMapType.Satellite theMap.showsUserLocation = true }

MapKitView

Our map type is Satellite but you can also choose MKMapType.Standard and MKMapType.Hybrid much like you would the Maps app on our iPhones.

The variable showsUserLocation will add the blinking blue dot to our map to show where we currently are.

As one might guess, this function gets called every time our location changes.

func locationManager (manager:CLLocationManager, didUpdateLocations locations:[ AnyObject ]) { theLabel.text = " \( locations[ 0 ] ) " myLocations.append(locations[ 0 ] as CLLocation)

The first thing we do is update theLabel ’s text with the details about our location. This will show all the interesting details at the bottom of our app including our longitude, latitude, how fast we are moving, and details about what time it is.

Notice how locations is an array of CLLocation ’s. In my experimentations, it seems like this array always only has 1 value. This is why I’m accessing the 0th (first) index of the array. I imagine this might have multiple values if we are tracking more than one object. If anyone would like to enlighten me, that would be great :)

We add this location to the array we created for holding all of our locations named myLocations .

let spanX = 0.007 let spanY = 0.007 var newRegion = MKCoordinateRegion(center: theMap.userLocation.coordinate, span: MKCoordinateSpanMake(spanX, spanY)) theMap.setRegion(newRegion, animated: true )

theMap.userLocation.coordinate

if (myLocations.count > 1 ){ var sourceIndex = myLocations.count - 1 var destinationIndex = myLocations.count - 2

myLocations

let c1 = myLocations[sourceIndex].coordinate let c2 = myLocations[destinationIndex].coordinate var a = [c1, c2]

coordinate

CLLocation

CLLocationCoordinate2D

a

var polyline = MKPolyline(coordinates: &a, count: a.count) theMap.addOverlay(polyline) } }

MKPolyline

CLLocationCoordinate2D

a

&

Finally, we add our polyline to the theMap as an overlay.

We are not quite done yet, even tho we added the line to the map, the map has no idea how to actually draw it. We have to specify a renderer for it, which we will talk about next.

mapView rendererForOverlay

We are inheriting this method from our MKMapView delegation. This method will be called whenever the MKMapKitView has to render an overlay.

func mapView (mapView: MKMapView ! , rendererForOverlay overlay: MKOverlay ! ) -> MKOverlayRenderer ! { if overlay is MKPolyline {

MKPolyline

var polylineRenderer = MKPolylineRenderer(overlay: overlay)

MKPolylineRenderer

polyline

didUpdateLocation

polylineRenderer.strokeColor = UIColor.blueColor() polylineRenderer.lineWidth = 4 return polylineRenderer } return nil }

polylineRender

MKPolyline

nil

Conclusion

Well, that was a lot of fun and I’m really happy with the results. I was watching that little car drive around the whole time I was writing this tutorial. I don’t know what sorta freeways let you go 30 mph, but whatever ;)

We can do a lot with this framework. One thing I was doing by accident at first was using Apple’s MKDirections API to ask for directions between the two locations to draw a line before I realized I didn’t have to do that at all. I actually had the code mostly working, but maybe I will save that for a tutorial some other day.

Anyhoo, hope this is useful and I hope you all enjoy learning Swift as much as I am :)