ardevd
ardevd

Reputation: 3407

MKLocalSearchRequest giving me weird results

So Ive implemented a searchBar for my maps application and its giving me some weirds results. If I search for "Oslo" for instance, it points me to a very specific but weird spot north of the city and zoomed far in. There must be something I've done wrong in code here. Anyone able to spot the issue?

// When user submits search query
func searchBarSearchButtonClicked(searchBar: UISearchBar){
    // resign first responder and dismiss the searchbar.
    searchBar.resignFirstResponder()
    dismissViewControllerAnimated(true, completion: nil)

    // Create and start search request
    localSearchRequest = MKLocalSearchRequest()
    localSearchRequest.naturalLanguageQuery = searchBar.text
    localSearch = MKLocalSearch(request: localSearchRequest)

    localSearch.startWithCompletionHandler { (localSearchResponse, error) -> Void in

        if localSearchResponse == nil{
            let alertController = UIAlertController(title: nil, message: "Place Not Found", preferredStyle: UIAlertControllerStyle.Alert)
            alertController.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.Default, handler: nil))
            self.presentViewController(alertController, animated: true, completion: nil)
            return
        }

        let center = CLLocationCoordinate2D(latitude: localSearchResponse!.boundingRegion.center.latitude, longitude: localSearchResponse!.boundingRegion.center.longitude)
        self.updateCurrentMapRegion(center, distance: 5000)
        NSNotificationCenter.defaultCenter().postNotificationName("LocationUpdate", object: nil, userInfo: ["latitude": center.latitude, "longitude": center.longitude])
    }
}

Also, one issue is that I've hardcoded the distance to 5000 meters when updating the map region after getting a search result. How can I handle this in a more dynamic manner?

Whats the alternative to using MKLocalSearchRequest() which in my mind sounds like something you should use when looking for stuff nearby and not larger entities such as cities, etc.

Upvotes: 1

Views: 2279

Answers (2)

NiteOwl
NiteOwl

Reputation: 81

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 this in
answer

Upvotes: 1

Edward Jiang
Edward Jiang

Reputation: 2433

First thing first: MKLocalSearch is the correct API for you to be using, even though it might sound a bit weird for what you're doing!

MKLocalSearch gets you a list of locations, and then returns a bounding box around the locations to best fit what it thinks you're looking for. I tried running your code and found this for Oslo:

Oslo place mark in bounding box

The problem you're experiencing is that you're using the center of the bounding box as your pin location, instead of the Oslo placemark.

So instead of your line of code here:

let center = CLLocationCoordinate2D(latitude: localSearchResponse!.boundingRegion.center.latitude,
    longitude: localSearchResponse!.boundingRegion.center.longitude)

You would use:

let center = localSearchResponse?.mapItems.first?.placemark.coordinate

(This is an optional, but you can choose how to handle it. I'll show you my preferred way in a bit.)

In addition, this solves your problem about how far to zoom in. Simple, you can use the region's bounding box as a zoom level. I'm not sure how your updateCurrentMapRegion:distance method works, but MKMapView has the convenient setRegion:animated method that you can use (if you have access).

mapView.setRegion(localSearchResponse!.boundingRegion, animated: true)

To sum this up, if you have a reference to MapView, you should be able to replace your completion block with this and have it work:

guard let localSearchResponse = localSearchResponse, mapItem = localSearchResponse.mapItems.first else {
    let alertController = UIAlertController(title: nil, message: "Place Not Found", preferredStyle: UIAlertControllerStyle.Alert)
    alertController.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.Default, handler: nil))
    self.presentViewController(alertController, animated: true, completion: nil)
    return
}

let center = mapItem.placemark.coordinate
self.mapView.setRegion(localSearchResponse.boundingRegion, animated: true)
NSNotificationCenter.defaultCenter().postNotificationName("LocationUpdate", object: nil, userInfo: ["latitude": center.latitude, "longitude": center.longitude])

In this block, I also replaced your if statement with a guard to set both values, so we no longer have to force unwrap optionals. If you can't have access to mapView in this method, you can probably switch up the updateCurrentMapRegion:center so that it fits better, or do some math to make the bounding region fit within those values.

Upvotes: 3

Related Questions