DEV Community

Avelyn Hyunjeong Choi
Avelyn Hyunjeong Choi

Posted on • Edited on

Introduction to Maps with Swift

In this blog, I will be using two frameworks for locations, CoreLocation and MapKit.

  • CoreLocation: used to manage operations related to coordinates and address
  • MapKit: used to manage any operations related to drawing a map on the screen

Forward Geocoding

  • translate a human-readable address -> coordinates (latitude + longitude)
  • submit the address to Apple's geocoding server as a background task
import UIKit

// MARK: 1. import the CoreLocation Library
// - has methods and properties that allow you to manage addresses and coordinates
import CoreLocation

class ForwardGeoVC: UIViewController {

  // MARK: Outlets
  @IBOutlet weak var streetTF: UITextField!
  @IBOutlet weak var cityTF: UITextField!
  @IBOutlet weak var countryTF: UITextField!
  @IBOutlet weak var coordinatesLabel: UILabel!

  // MARK: 2. Geocoder object
  let geocoder = CLGeocoder()

  override func viewDidLoad() {
    super.viewDidLoad()
  }

  @IBAction func fetchCoordinates(_ sender: Any) {
    guard let street = streetTF.text,
          let city = cityTF.text,
          let country = countryTF.text
    else {return}

    print("\(country), \(city), \(street)")

    getLocation(address: "\(country), \(city), \(street)")
  }

  // helper function
  func getLocation(address: String) {
    // MARK: 3. Forward geocoding request
    // - Taking a human readable addresss and converting it to a coordinate

    geocoder.geocodeAddressString(address) { results, error in
      print("Sent request to geocoding service, waiting for response")

      // unsuccessful
      if (error != nil) {
        print("Error occured during geocoding request:")
        print(error ?? "")
        self.coordinatesLabel.text = "An error occured, try again later."
        return
      }

      // success
      if(results != nil) {
        if(results?.count == 0) {
          // not able to find a coordinate
          print("No coordinates found for this address")
          self.coordinatesLabel.text = "No coordinates found for this address"
        } else {
          // able to find a coordinate
          print("Coordinate found")
          let placemark: CLPlacemark = (results?.first)!
          print(placemark)

          // extract the relevant data (lat, long)
          if let lat = placemark.location?.coordinate.latitude,
             let long = placemark.location?.coordinate.longitude {
            print("Coordinate: \(lat), \(long)")
            self.coordinatesLabel.text = "\(lat), \(long)"
          } else {
            print("Could not extract coordinates")
            self.coordinatesLabel.text = "Could not extract coordinates"
          }
        }
      }
    }
  }

}
Enter fullscreen mode Exit fullscreen mode

Screen
Image description

Reverse Geocoding

  • translate a set of coordinates (latitude + longitude) -> human readable address
import UIKit

// MARK: 1. import CoreLocation
import CoreLocation

class ReverseGeoVC: UIViewController {

  // MARK: Outlets
  @IBOutlet weak var latitudeTF: UITextField!
  @IBOutlet weak var longitudeTF: UITextField!
  @IBOutlet weak var addressLabel: UILabel!

  // MARK: 2. Geocoder object
  let geocoder = CLGeocoder()

  override func viewDidLoad() {
    super.viewDidLoad()

  }

  @IBAction func fetchAddress(_ sender: Any) {
    guard let lat = latitudeTF.text,
          let long = longitudeTF.text
    else {return}

    print("Got coordinates: (\(lat), \(long))")

    getAddress(latitude:lat, longitude: long)
  }

  // helper function
  func getAddress(latitude:String, longitude:String) {
    // MARK: 3. Reverse geocoding request
    // - Taking a coordinate and converting it to a human readable addresss
    guard let latDouble = Double(latitude),
          let longDouble = Double(longitude)
    else {return}

    let location = CLLocation(latitude: latDouble, longitude: longDouble)

    geocoder.reverseGeocodeLocation(location) { results, error in
      print("Sent request to geocoding service, waiting for response")

      if let err = error {
        print("Error occured during geocoding request: \(err)")
        self.addressLabel.text = "An error occured, try again later."
      }

      if let res = results {
        if (res.count == 0) {
          // not able to find a coordinate
          print("No addresses found for this coordinate")
        } else {
          // able to find a coordinate
          print("Address found")
          let placemark:CLPlacemark = res.first!
          print("Placemark: \(placemark)")

          //compose an actual address
          let name = placemark.name ?? ""
          let street = "\(placemark.subThoroughfare ?? "") \(placemark.thoroughfare ?? "")"
          let city = placemark.locality ?? ""
          let province = placemark.administrativeArea ?? ""
          let country = placemark.country ?? ""

          let address = "\(name) \(street), \(city), \(province), \(country)"
          print("Final address: \(address)")
          self.addressLabel.text = address
        }
      }
    }
  }

}
Enter fullscreen mode Exit fullscreen mode

Screen
Image description

Main Map View Controller

import UIKit

// MARK: 1. import MapKit
import MapKit

class MapVC: UIViewController {

  // MARK: 2. Create an outlet for your map
  @IBOutlet weak var mapView: MKMapView!

  override func viewDidLoad() {
    super.viewDidLoad()

    // MARK: 3. Code to configure the map
    // See:  https://guides.codepath.com/ios/Maps#set-up-initial-properties

    // span  = describes the zoom level of your map
    // smaller numbers = more zoomed in
    // larger numbers = more zoomed out
    // 0.01 = street level zoom
    let zoomLevel = MKCoordinateSpan(latitudeDelta: 0.05, longitudeDelta: 0.05)

    // region = visible area of the map --> center of your map
    let centerOfMap = CLLocationCoordinate2D(latitude: 43.7957894, longitude: -79.3489909)
    let visibleRegion = MKCoordinateRegion(center: centerOfMap, span: zoomLevel)

    // setup the map to show this region
    mapView.setRegion(visibleRegion, animated: true)

    // MARK: 4. Add a pin on the map
    // See: https://guides.codepath.com/ios/Maps#mkpointannotation
    let pin = MKPointAnnotation()
    pin.coordinate = centerOfMap
    pin.title = "Seneca College - Newnham Campus"
    mapView.addAnnotation(pin)
  }

}
Enter fullscreen mode Exit fullscreen mode

Screen
Image description

Top comments (0)