Reputation: 3407
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
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
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:
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