0

I'm building a a simple application that allows a user to save their location for later.

The Goal: A user pins their address when at a business, and we save the name of the business

My approach: I'm requesting the location from a locationManager. Then I reverse geocode the CLLocation into a CLPlacemark. Since the placemark isn't recognizing the business name, I start a MKLocalSearch for "restaurants nearby". The response.mapItems are returning locations in completely different cities.

I have specified the region and verified that the placemark is correctly returning the user's address. So, I believe the issue lays within the MKLocalSearch.

Why does it return results for different cities?

Updated: All code From View Controller

class ViewController: UIViewController {

    let locationManager = CLLocationManager()
    var places = [MKMapItem]()

    let naturalLanguageQuery = "closest places to eat"
    let queries = ["restaurants", "places to eat", "breakfast", "lunch", "dinner"]

    override func viewDidLoad() {
        super.viewDidLoad()
        //  Do any additional setup after loading here
        locationManager.delegate = self
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
        if CLLocationManager.authorizationStatus() == .notDetermined {
            locationManager.requestWhenInUseAuthorization()
        }
    }

    @IBAction func getLocation() {
        if CLLocationManager.authorizationStatus() == .authorizedWhenInUse {
            locationManager.requestLocation()
        }
    }

    func add(placemark: CLPlacemark) {
        search(placemark: placemark, index: self.queries.count - 1)
    }

    func searchCompleted(placemark: CLPlacemark) {
        guard let foo = Scraper.shared.sortByDistance(userPlacemark: placemark, items: places) else { return }
        for item in Scraper.shared.filterForUnique(items: foo) {
            print(item)
            if item.placemark.addressString == placemark.addressString {

            }
        }
    }

    func search(placemark: CLPlacemark, index: Int) {
        let request = MKLocalSearchRequest()
        guard let coordinate = placemark.location?.coordinate else { return }
        request.region = MKCoordinateRegionMakeWithDistance(coordinate, 1600, 1600)
        request.naturalLanguageQuery = queries[index]
        MKLocalSearch(request: request).start { (response, error) in
            guard error == nil else { return }
            guard let response = response else { return }
            guard response.mapItems.count > 0 else { return }

            for item in response.mapItems {
                self.places.append(item)
            }

            if index != 0 {
                self.search(placemark: placemark, index: index - 1)
            } else {
                self.searchCompleted(placemark: placemark)
            }
        }
    }
}

extension ViewController: CLLocationManagerDelegate {
    func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        let geocoder = CLGeocoder()
        if let loc = locations.last {
            geocoder.reverseGeocodeLocation(loc) { (placemarks, error) in
                if let error = error {
                    print("error")
                } else {
                    if let placemark = placemarks?.first {

                        print(placemark.debugDescription)
                        self.add(placemark: placemark)
                    }
                }
            }
        }
    }

    func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        print(error.localizedDescription)
    }
}
Michael Hulet
  • 3,253
  • 1
  • 16
  • 33
Richard Poutier
  • 207
  • 2
  • 10
  • Is this happening in the simulator or on an actual device? – binaryPilot84 Sep 06 '18 at 17:45
  • It's happening on both. However, the TestFlight betas are having the issue worse than the simulator. – Richard Poutier Sep 06 '18 at 17:51
  • @johnayers it's happening on both! Any ideas why? – Richard Poutier Sep 06 '18 at 18:31
  • 1
    Can you post the rest of the viewController code? – binaryPilot84 Sep 07 '18 at 01:16
  • @JohnAyers added – Richard Poutier Sep 07 '18 at 17:33
  • I've been troubleshooting your code in a simulator so I want to ensure a couple things. First, I'm assuming you have, but did you add a pList entry for Location Usage? Second, I placed 2 print statements in your search function; the first, print("Loc: \(coordinate)"), beneath your "guard let coordinate...." statement. The second, print("Found: \(item.placemark.coordinate)"), was in your "for item in ..." loop. Each of these is showing the correct simulated coordinates I specified in the simulator and it's showing locations I request. (see next comment) – binaryPilot84 Sep 08 '18 at 14:40
  • Here's where it gets weird. I specified locations in Apple Park, Seattle, San Antonio, Houston, and London. Each of these locations returned items within the coordinate region. When I specified a random location in Mexico, that's when I got information specific to my city. – binaryPilot84 Sep 08 '18 at 14:40
  • @JohnAyers and that's where it's been causing a lot of problems. I'm running iOS 12 beta, and it's working fairly consistent on my phone. However, our TestFlight users are in iOS 11. I don't know if it has something to due with the new updated Maps. I can see how the MKLocalSearch would be improved from iOS 11 to iOS 12. Other than this however, it's hard to even reach out to Apple since it's somewhat difficult to replicate consistently. – Richard Poutier Sep 10 '18 at 17:50
  • have you tested in a iOS 12 simulator or just a device? I'd be interested in what your results are if you specify a random location outside of your standard major locations. The simulator I tested (iOS 11) gave normal results up until I specified a small villa in Mexico. Multiple locations in the US and Europe came back normal. I didn't test much of small-town USA or elsewhere, so that does remain to be seen. – binaryPilot84 Sep 10 '18 at 17:54
  • Simulator and device both running on iOS 12. I've tested numerous "smaller" towns in the LA County and Ventura County area and I'm getting results for different cities which is weird. I may consider making the switch to Google Places API. Wanted to stay away from this but this issue has persisted for almost a month now. – Richard Poutier Sep 10 '18 at 18:14
  • 1
    Unfortunately, that may be the best solution. I think Apple Maps still has a year or so before their new mapping functionality is truly functional. – binaryPilot84 Sep 10 '18 at 18:21
  • @JohnAyers definitely a very interesting ambiguity in the Apple MapKit API. – Richard Poutier Sep 10 '18 at 18:42
  • You shouldn't use MKLocalSearchRequest() instead use MKLocalSearchCompleter which gives better results and is used in current Apple Maps. You can learn how to implement it here: [MKLocalSearchCompleter](https://stackoverflow.com/a/38497997/8420544) – Adam Linke Dec 17 '18 at 21:16

1 Answers1

1

Given your code, it appears your logic is correct, but depending on the location, you may not get what you want. Apple's documentation for the MKCoordinateRegion states that "specifying a region does not guarantee that the results will all be inside the region. It is merely a hint to the search engine." MKLocalSearch Documentation

binaryPilot84
  • 994
  • 6
  • 20