iOS App Development iOS Swift Tutorial iOS9 Uber

Uber Part 2 : CoreLocation and MapKit

In this tutorial we will use CoreLocation and Mapkit to get the current user location , set the map zoomed in on the current location and we should be able to get the location updated when we pan the mapview. This updated location is what we will be using for pickup. This is the part 2 so make sure you check Part1 before we continuing further.

Before we go ahead create neccessary outlets for mapView, driverView and address.

CoreLocation

We will be using the latest method on the CoreLocation Manager called requestLocation which we will use to get the current Location only once instead of monitoring for the location changes continously.

Also we need to set the necessary setup for getting corelocation to work . For more information take a look at how to set this up . We also need to implement the CLLocationManagerDelegate which is necessary to get the location updates. In thedidUpdateLocation we find the first location and set themapview region to zoom in on our current location with the location as the center and 1500meter span. Here are the parameters for the MKCoordinateRegionMakeWithDistance method.

Parameters

centerCoordinate

The center point of the new coordinate region.

latitudinalMeters

The amount of north-to-south distance (measured in meters) to use for the span.

longitudinalMeters

The amount of east-to-west distance (measured in meters) to use for the span.

MapKit

MapView has a property called centerCoordinate which we can use as a reference for the pickup location. Also if you see the realuber app we can see that there is one marker which in our case in the location marker and we can pan themapview to set the pickup location as per our need. To get the update centerCoordinate we need to implement the MKMapViewDelegate protocol and implement the method regionDidChangeAnimated .

Also it wouldn’t make sense to show the latitude and longitude to the user so we need to reverseGeocode the latitude and longitude into the a human readable address and update the address label.

One more thing to note about the CLGeocode is that only one request can be active at any point in time so we need to cancel any existing geocoding request before submitting for more.

    func geoCode(location : CLLocation!){
        /* Only one reverse geocoding can be in progress at a time hence we need to cancel existing
        one if we are getting location updates */
        geoCoder.cancelGeocode()
        geoCoder.reverseGeocodeLocation(location, completionHandler: { (data, error) -> Void in
            guard let placeMarks = data as [CLPlacemark]! else {
                return
            }
            let loc: CLPlacemark = placeMarks[0]
            let addressDict : [NSString:NSObject] = loc.addressDictionary as! [NSString: NSObject]
            let addrList = addressDict["FormattedAddressLines"] as! [String]
            let address = ", ".join(addrList)
            print(address)
            self.address.text = address
            self.previousAddress = address
        })

    }
    
    func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        let location: CLLocation = locations.first!
        self.mapView.centerCoordinate = location.coordinate
        let reg = MKCoordinateRegionMakeWithDistance(location.coordinate, 1500, 1500)
        self.mapView.setRegion(reg, animated: true)
        geoCode(location)
    }
    
    
    func locationManager(manager: CLLocationManager, didFailWithError error: NSError) {
        print(error)
    }
    
    func mapView(mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
        let location = CLLocation(latitude: mapView.centerCoordinate.latitude, longitude: mapView.centerCoordinate.longitude)
        geoCode(location)
    }

Also create an IBAction for the request pickup. This is where we implement the logic of submitting the pickup request to the backend which will be sent to the driver app and then the we display the information of the selected driver. In our case for the simulation purpose we create a dummy view which is hidden and then after the request button is clicked after 3 seconds we change the hidden property to false. In the next part of the tutorial we will see how to build custom views.

About the author

Shrikar

Backend/Infrastructure Engineer by Day. iOS Developer for the rest of the time.

  • http://lm-infosec.com Inno Orikiiriza

    Hello,

    Waiting for this section’s Part 3, hope it will be available?

    Thanks!

    • https://shrikar.com shrikar

      Yes I will get that thing done soon

      • Kevin Maynard

        Will you consider posting your project where we could download? It may be because of changes to Swift since this was written, but I am getting all sorts of errors.

      • Tyler Ruby

        Please make Part 3! I will personally pay :)

      • Liz Goldston

        I would love to get Part 3 as I am working on an app similar to this

  • James

    I get error
    Error Domain=kCLErrorDomain Code=0 “The operation couldn’t be completed. (kCLErrorDomain error 0.)”
    I have made sure I have allowed location simulation. What are other possible sources for error

    • https://shrikar.com shrikar

      I know it might sound stupid. But sometimes recreating the device or trying on a different simulator works.

      • Varun

        Hi shrikar. I am also getting the same thing and won’t go even if I clear the cache. Also after debugging it looks like it is not going to geocode function. Can you help.?

        • Troy Leak

          Don’t know if it helps you, but I needed to add NSLocationAlwaysUsageDescription to info.plist with a text field indicating why you need access. After that the modal dialogue asking if you want to allow access always to this app will appear, and when you grand permission it should work. I figured this was the problem after placing breakpoints and determining that the geocoder function was not being called.

          This Stackoverflow post had the info I needed: https://stackoverflow.com/questions/26434250/cllocationmanagerdelegate-methods-not-being-called-in-swift-code/26434314#26434314

          Hope this helps someone else out there!

  • James

    Could you upload the .xcodeproj

  • James

    could I get your email?

  • Rafael Beltrao

    I keep getting “cannot invoke ‘requestLocation’ with no arguments… what can I do?

  • George Schmiester

    Great tutorial! Unfortunately I can’t get the following code working on Swift2.0 (Xcode 7). Is there an updated string?

    geoCoder.reverseGeocodeLocation(location: completionManager: { (data, error) -> void in guard let placeMarks = data as [CLPlacemark]! else {
    return
    }

  • George Schmiester

    let address = “,”.join(addrList) is apparently no longer used in swift 2.0 as join has been replaced by joinwithseperator. does anyone have the revised line to work in swift 2.0?

  • George Schmiester

    Hope all is well Shrikar, is part 3 coming?

  • Abudoula Nulumu

    Hi Shrikar, I love you vedio. Thank you for sharing this. My have problem.
    let address = “,”.join(addrList)
    this is come out wrong. Can you please help me solve this problem.
    Thank you.

    • Harun Jantrik

      i got it..just change to
      let address = addrList.joinWithSeparator(“, “)

      • Raul Gutierrez

        This worked for me! Thanks to all for this helpful post.

  • Akash K

    Hi Shrikar. Just curious when you would be posting the part 3?

  • Tyler Ruby

    Can we please get a Part 3 now?

  • Tim Vogt

    I get lots of code error any post with the code?
    and part 3?

/* ]]> */