Core Location Tutorial for iOS: Tracking Visited Locations

In this Core Location tutorial, you will learn how to use visit monitoring to track a user’s visited locations. By Andrew Kharchyshyn.

Leave a rating/review
Download materials
Save for later
Share

Introduction

iOS has very powerful APIs for tracking user locations and working with maps. You might be making an app for your local café and want to notify the user of special offers when they are nearby. Or, you’re making a music player and you want to start playing some bouncy beats when the user enters a gym. Tracking location all the time, however, can drain a battery really fast! In this Core Location tutorial, you’ll learn how to use some of the lesser-known, but very powerful, capabilities of the framework. You’ll learn how to create an app that logs user movements during the day but also doesn’t drain much of a device’s battery.

In this tutorial, you’ll make a travel logging app. Imagine you’re traveling to a new city. Instead of keeping a journal, this app will automatically track locations you visit, so you can remember them later and compare them with your friends.

Here’s what this app will do:

  • Track the user’s location, even when the app is not open.
  • When the app logs a new location, send the user a local notification.
  • Save those locations in a file.
  • Display a list of logged locations.
  • Display a map with user location and logged locations.
  • Allow users to manually log their current location.

Core Location visited locations tutorial finished app

Without further ado, it’s time to get into it.

Getting Started

First, download the project materials using the Download Materials link at the top or bottom of this tutorial. Open the starter project. Right now, the app doesn’t do much. On the first tab, you have an empty list with locations. On the second tab, you’ll see an empty map view.

Core Location tutorial starter app

Here’s what’s in the starter project:

AppDelegate.swift

You have two additional imports at the top of the file:

import CoreLocation
import UserNotifications

The CoreLocation framework listens to user location updates. You’ll use the UserNotifications framework to show banner notifications when the app logs a new location.

You can also see two extra properties in the class declaration:

let center = UNUserNotificationCenter.current()
let locationManager = CLLocationManager()

Through these two properties, you’ll access the API of the two frameworks above.

PlacesTableViewController.swift

This is the first tab of the app — the UITableViewController subclass — with an empty datasource implementation. If you need a better understanding of any of the methods, check out this awesome course on table views before you continue.

MapViewController.swift

This is the view controller for the second tab. You have the MKMapView hooked up from the storyboard. You also have an IBAction for the plus button in the navigation bar.

Location.swift

This is the model class. It has five stored properties:

let latitude: Double
let longitude: Double
let date: Date
let dateString: String
let description: String
  • latitude and longitude are what you’d expect them to be: the coordinates of the location.
  • The date is the exact date when this location was logged.
  • dateString is a human readable version of the date.
  • description is a human readable address of the location.

There is also a computed property to convert the Location object to CLLocationCoordinate2D, which will be useful later in the tutorial.

There are two initializers for this class; you’ll learn about them later in this tutorial.

You need to save objects of this class on disk. In order to do that, this class conforms to Codable. Codable is a Swift 4 language feature that allows you to encode and decode objects easily. For more information on this feature, check out our tutorial on Codable.

LocationsStorage.swift

Last but not least, with this singleton, you’ll save locations to the documents folder of the app.

This class has a couple of properties to do the writing and reading from the disk:

private let fileManager: FileManager
private let documentsURL: URL

It also has a property to access all logged locations, which, for now, is set to an empty array in the initializer:

private(set) var locations: [Location]

Now that you’re up to speed with the initial code, it’s time to add some new code!

Core Location: Asking for User Locations

The first step is to ask permission to track the user’s location. In the age of privacy scandals, Apple stands pretty strong on keeping users in charge of which data an app can gather. That’s why it is very important to properly ask users to allow the app access to gather the required data.

Providing a Proper Description

To gather location changes data, you need to set two special strings in the Info.plist file:

Setting up Info.plist for Core Location

The app presents these strings when it asks for permission. Feel free to change the prompts to any text you like as long as the text fulfills the following requirements:

  • Encourage users to give you the access.
  • Let users know exactly how, and for what reason, the data is being collected.
  • The statement is 100% true.

Asking for Locations Permissions

Open AppDelegate.swift and add this line before the return statement in application(_:didFinishLaunchingWithOptions:):

locationManager.requestAlwaysAuthorization()

With this line, you ask users to allow the app to access location data both in the background and the foreground.

Build and run the project. You should get a dialog similar to this one, but it will include the strings you set in the Info.plist file earlier in the tutorial:

Core Location permission alert

Tap Always Allow.

Note: The user may restrict the access to location data for background or for both; in this case, it’s the developer’s responsibility to gracefully handle those cases properly. To keep things simple for this tutorial, you’ll assume that the user selects Always Allow.

Asking for Notifications Permissions

Location permissions are not the only permissions you need: To show a user notifications, you need to ask permission.

To do so, you don’t have to specify any additional strings. Just add this code right above the line you just added:

center.requestAuthorization(options: [.alert, .sound]) { granted, error in
}

Here, you pass options to specify what kind of notifications you want to post. You also include an empty closure because you assume, for this tutorial, that users always give you permission. You can handle the denial in this closure.

Build and run. You should see this dialog:

Notifications permission alert

Tap Allow.