Home iOS & Swift Books iOS Apprentice

27
Get Location Data Written by Eli Ganim

Heads up... You're reading this book for free, with parts of this chapter shown beyond this point as scrambled text.

You can unlock the rest of this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.

You are going to build MyLocations, an app that uses the Core Location framework to obtain GPS coordinates for the user’s whereabouts, MapKit to show the user’s favorite locations on a map, the iPhone’s camera and photo library to attach photos to these locations, and finally, Core Data to store everything in a database. Phew, that’s a lot of stuff!

The finished app looks like this:

The MyLocations app
The MyLocations app

MyLocations lets you keep a list of spots that you find interesting. Go somewhere with your iPhone or iPad and press the Get My Location button to obtain GPS coordinates and the corresponding street address. Save this location along with a description and a photo in your list of favorites for reminiscing about the good old days.

Think of this app as a “location album” instead of a photo album.

To make the workload easier to handle, you’ll split the project up into smaller chunks:

  1. You will first figure out how to obtain GPS coordinates from the Core Location framework and how to convert these coordinates into an address, a process known as reverse geocoding. Core Location makes this easy, but due to the unpredictable nature of mobile devices, the logic involved can still get quite tricky.

  2. Once you have the coordinates, you’ll create the Tag Location screen that lets users enter the details for the new location. This is a table view controller with static cells, very similar to what you’ve done previously in Bullseye’s highscores screen.

  3. You’ll store the location data into a Core Data store. For the last app you saved app data into a .plist file, which is fine for simple apps, but pro developers use Core Data. It’s not as scary as it sounds!

  4. Next, you’ll show the locations as pins on a map using the MapKit framework.

  5. The Tag Location screen has an Add Photo button that you will connect to the iPhone’s camera and photo library so users can add snapshots to their locations.

  6. Finally, you’ll make the app look good using custom graphics. You will also add sound effects and some animations to the mix.

Of course, you are not going to do all of that at once. In this chapter, you will do the following:

  • Get GPS Coordinates: Create a tab bar based app and set up the UI for the first tab.
  • CoreLocation: Use the CoreLocation framework to get the user’s current location.
  • Display coordinates: Display location information on screen.

When you’re done with this chapter, the app will look like this:

The first screen of the app
The first screen of the app

Get GPS coordinates

First, you’ll create the MyLocations project in Xcode and then use the Core Location framework to find the latitude and longitude of the user’s location.

Creating the project

➤ Fire up Xcode and make a new project. Choose the Tabbed App template.

Choosing the Tabbed Application template
Rneofiqs mwe Lenper Ujcdikonauw yitwyopu

The app from the Tabbed Application template
Hki urm fhuv cle Pidnob Echtosejeuq kowmsuza

The storyboard from the Tabbed Application template
Zwi zvukknuozk vbew ybi Watsug Emkjukaruoq woyjfepe

The first tab

In this chapter, you’ll be working with the first tab only. In future chapters you’ll create the screen for the second tab and add a third tab as well.

The app only works in portrait
Lca ejr ifzx buslg az simbvouq

Changing the title of the Tab Bar Item
Pnojjozn cni bamsa aq tri Tog Pay Ugaq

First tab UI

You will now design the screen for this first tab. It gets two buttons and a few labels that show the user’s GPS coordinates and the street address. To save you some time, you’ll add all the outlets in one go.

@IBOutlet weak var messageLabel: UILabel!
@IBOutlet weak var latitudeLabel: UILabel!
@IBOutlet weak var longitudeLabel: UILabel!
@IBOutlet weak var addressLabel: UILabel!
@IBOutlet weak var tagButton: UIButton!
@IBOutlet weak var getButton: UIButton!
// MARK:- Actions
@IBAction func getLocation() {
  // do nothing yet
}
The design of the Current Location screen
Dxu honiqh en hgi Xityodn Zecufouq zvroix

The (Message Label) constraints
Xmo (Vahtetu Tijoz) sedxmyaazwd

Core Location

Most iOS devices have a way to let you know exactly where you are on the globe, either through communication with GPS satellites, or Wi-Fi and cell tower triangulation. The Core Location framework puts that power in your own hands.

Get your current location

Getting a location from Core Location is pretty easy, but there are some pitfalls that you need to avoid. Let’s start simple and just ask it for the current coordinates and see what happens.

import CoreLocation
class CurrentLocationViewController: UIViewController, 
                                     CLLocationManagerDelegate {
let locationManager = CLLocationManager()
@IBAction func getLocation() {
  locationManager.delegate = self
  locationManager.desiredAccuracy = 
                  kCLLocationAccuracyNearestTenMeters
  locationManager.startUpdatingLocation()
}
// MARK: - CLLocationManagerDelegate
func locationManager(_ manager: CLLocationManager, 
        didFailWithError error: Error) {
  print("didFailWithError \(error.localizedDescription)")
}

func locationManager(_ manager: CLLocationManager, 
  didUpdateLocations locations: [CLLocation]) {
  let newLocation = locations.last!
  print("didUpdateLocations \(newLocation)")
}

Ask for permission

➤ Add the following lines to the top of getLocation():

let authStatus = CLLocationManager.authorizationStatus()
if authStatus == .notDetermined {
  locationManager.requestWhenInUseAuthorization()
  return
}
Adding a new row to Info.plist
Evpapt o bos piw xi Asgu.nfumr

Adding the new item to Info.plist
Ufgawk dsu bat imag ri Utvi.jzung

Users have to allow your app to use their location
Adusb daje di ongub puiz izw ri obi qjaev nixufaif

didFailWithError The operation couldn’t be completed. (kCLErrorDomain error 1.)

Handle permission errors

➤ Add the following method to CurrentLocationViewController.swift:

// MARK:- Helper Methods
func showLocationServicesDeniedAlert() {
  let alert = UIAlertController(
    title: "Location Services Disabled",
    message: "Please enable location services for this app in Settings.",
    preferredStyle: .alert)

  let okAction = UIAlertAction(title: "OK", style: .default, 
                             handler: nil)
  alert.addAction(okAction)

  present(alert, animated: true, completion: nil)
}
if authStatus == .denied || authStatus == .restricted {
  showLocationServicesDeniedAlert()
  return
}
The alert that pops up when location services are not available
Nxi iquvz jpev vunf od qfof gixalaap xokxacoq ivo sit exaijeyqu

Location Services in the Settings app
Rihaquij Yatbutib uv fyi Xovwubdk iqx

didFailWithError The operation couldn’t be completed. (kCLErrorDomain error 0.)

Fake location on the simulator

➤ With the app running, from the simulator’s menu bar at the top of the screen, choose Debug ▸ Location ▸ Apple.

The simulator’s Location menu
Cro nucuvahex’b Qekuceen zewe

didUpdateLocations <+37.33259552,-122.03031802> +/- 500.00m (speed -1.00 mps / course -1.00) @ 6/30/17, 8:19:11 AM Israel Daylight Time
didUpdateLocations <+37.33241211,-122.03050893> +/- 65.00m (speed -1.00 mps / course -1.00) @ 6/30/17, 8:19:13 AM Israel Daylight Time
didUpdateLocations <+37.33240901,-122.03048800> +/- 65.00m (speed -1.00 mps / course -1.00) @ 6/30/17, 8:19:14 AM Israel Daylight Time

Asynchronous operations

Obtaining a location is an example of an asynchronous process.

Displaying coordinates

The locationManager(_:didUpdateLocations:) delegate method gives you an array of CLLocation objects that contain the current latitude and longitude coordinates of the user. These objects also have some additional information, such as the altitude and speed, but you won’t use those in this app.

var location: CLLocation?
func locationManager(_ manager: CLLocationManager, 
  didUpdateLocations locations: [CLLocation]) {
  let newLocation = locations.last!
  print("didUpdateLocations \(newLocation)")

  location = newLocation    // Add this
  updateLabels()            // Add this
}
func updateLabels() {
  if let location = location {
    latitudeLabel.text = String(format: "%.8f", 
                                location.coordinate.latitude)
    longitudeLabel.text = String(format: "%.8f", 
                                 location.coordinate.longitude)
    tagButton.isHidden = false
    messageLabel.text = ""
  } else {
    latitudeLabel.text = ""
    longitudeLabel.text = ""
    addressLabel.text = ""
    tagButton.isHidden = true
    messageLabel.text = "Tap ’Get My Location’ to Start"
  }
}
latitudeLabel.text = "\(location.coordinate.latitude)"

Format strings

Like string interpolation, a format string uses placeholders that will be replaced by the actual value during runtime. These placeholders, or format specifiers, can be quite intricate.

String(format: "%.8f", location.coordinate.latitude)
The app shows the GPS coordinates
Nro irb fciwz bji JLN waowmiloyej

override func viewDidLoad() {
  super.viewDidLoad()
  updateLabels()
}
What the app looks like when you start it
Bwov gjo ofl haoqh hoji vdif fiu wloft eg

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.

Have feedback to share about the online reading experience? If you have feedback about the UI, UX, highlighting, or other features of our online readers, you can send them to the design team with the form below:

© 2021 Razeware LLC

You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.

Unlock Now

To highlight or take notes, you’ll need to own this book in a subscription or purchased by itself.