Obtaining a user's location

Once your app has access to location data, you can use the location manager to begin observing a user's location, the direction in which a user is heading, and more. For now, you will focus on obtaining the user's current location. The GeofenceViewController already contains a method, called showCurrentLocation(), that is responsible for asking the location helper for a current location. If you examine this method closely, you'll find that it also asks the location helper for a location name by calling getLocationName(for:_:) and passing the obtained location to this method. The showCurrentLocation() method also uses the obtained location to focus a map view on the user's location by calling setRegion(_:animated:) on the map view.

Since the view controller is already fully prepared to handle location updates, all you need to do is add the proper implementations for getLatestLocation(_:) and getLocationName(for:_:). Begin by adding the following implementation for getLatestLocation(_:):

func getLatestLocation(_ completion: @escaping (CLLocation) -> Void) {
  if let location = trackedLocations.last {
    completion(location)
  } else if CLLocationManager.locationServicesEnabled() {
    latestLocationObtainedCallback = completion
    locationManager.startUpdatingLocation()
  }
}

The preceding method first checks whether a location has already been obtained. If it has, then the latest obtained location is returned. If there is no existing location, the code checks whether location services are enabled. It's always good practice to check whether the location service you are about to use is actually available. If location services are available, the completion callback is stored in the helper, and the location manager is told to start monitoring the user's location by calling startUpdatingLocation().

Calling startUpdateLocation() will make the location observer continuously monitor the user's GPS location, and will send any relevant updates to its delegate by calling locationManager(_:didUpdateLocations:). This method will always receive one or more new locations that the manager has obtained, where the latest location will be the last item in the list of obtained locations. Add the following implementation for this method to the CLLocationManagerDelegate extension of LocationHelper:

func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
  latestLocationObtainedCallback?(locations.last!)
  latestLocationObtainedCallback = nil
  locationManager.stopUpdatingLocation()

  trackedLocations += locations
}

The implementation for locationManager(_:didUpdateLocations:) is fairly straightforward: the latest location is passed to the callback, and the callback is removed to prevent subsequent location updates from triggering the callback unexpectedly. Also, the location manager is told to stop monitoring the user's location by calling stopUpdatingLocation(). Lastly, the obtained locations are stored for later use.

It's always good practice to make the location manager stop monitoring location updates if you won't be needing updates any time soon. Monitoring location updates has a pretty significant impact on battery life, so you shouldn't spend more time tracking a user's location than needed.

Now that you can retrieve the user's location, the last step is to also retrieve the location name, by implementing getLocationName(for:_:_) in the location helper. Add the following implementation for this method to the location helper:

func getLocationName(for location: CLLocation, _ completion: @escaping (String) -> Void) {
  let geocoder = CLGeocoder()
  geocoder.reverseGeocodeLocation(location) { placemarks, error in
    guard error == nil else {
      completion("An error ocurred: (error?.localizedDescription ?? "Unknown error")")
      return
    }

    completion(placemarks?.first?.name ?? "Unkown location")
  }
}

The preceding code uses a CLGeocoder to find a placemark that corresponds with the user's current location. Note that this feature uses an internet connection, so the name lookup will only work if the user has an internet connection. Regular GPS-related features do not require internet access, so your app can monitor and track a user's location even if they don't have an active internet connection.

Try running your app now—you should be able to see the user's current location on the map, and the location name, latitude, and longitude should be displayed on the screen as well. Now that you know how to obtain a user's location, let's see how you can efficiently subscribe your app to follow changes in a user's location.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.22.249.158