My app currently has a local search which adds annotations for the search results. I want to set it up where when you select the annotation and click the call out button, it will open in the Maps application with directions to the annotation from the current device location. I'm having a few problems with this.
First of all, my call out button on the annotation does not appear. Secondly, I don't think I am detecting the selected annotation correctly.
Here is my code for the search and selected annotation:
func performSearch() {
matchingItems.removeAll()
let request = MKLocalSearchRequest()
request.naturalLanguageQuery = searchText.text
request.region = mapView.region
let search = MKLocalSearch(request: request)
search.startWithCompletionHandler({(response:
MKLocalSearchResponse!,
error: NSError!) in
if error != nil {
println("Error occured in search: \(error.localizedDescription)")
} else if response.mapItems.count == 0 {
println("No matches found")
} else {
println("Matches found")
for item in response.mapItems as! [MKMapItem] {
println("Name = \(item.name)")
println("Phone = \(item.phoneNumber)")
self.matchingItems.append(item as MKMapItem)
println("Matching items = \(self.matchingItems.count)")
var annotation = MKPointAnnotation()
var coordinates = annotation.coordinate
annotation.coordinate = item.placemark.coordinate
annotation.title = item.name
self.mapView.addAnnotation(annotation)
}
}
})
}
func mapView(mapView: MKMapView!, annotationView view: MKAnnotationView!,
calloutAccessoryControlTapped control: UIControl!) {
if self.mapView.selectedAnnotations?.count > 0 {
if let selectedLoc = self.mapView.selectedAnnotations[0] as? MKAnnotation {
println("Annotation has been selected")
let currentLoc = MKMapItem.mapItemForCurrentLocation()
let mapItems = NSArray(objects: selectedLoc, currentLoc)
let launchOptions = [MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving]
MKMapItem.openMapsWithItems([selectedLoc, currentLoc], launchOptions: launchOptions)
}
}
}
Any help will be appreciated, thanks in advance.
For the first issue:
A callout button needs to be set explicitly in the viewForAnnotation
delegate method (default red pins don't have one). Here's a simple example of one possible implementation:
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
if annotation is MKUserLocation {
return nil
}
let reuseId = "pin"
var pinView = mapView.dequeueReusableAnnotationViewWithIdentifier(reuseId) as? MKPinAnnotationView
if pinView == nil {
pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
pinView!.canShowCallout = true
pinView!.pinColor = .Purple
//next line sets a button for the right side of the callout...
pinView!.rightCalloutAccessoryView = UIButton.buttonWithType(.DetailDisclosure) as! UIButton
}
else {
pinView!.annotation = annotation
}
return pinView
}
For the second issue:
First, in calloutAccessoryControlTapped
, the annotation is directly accessible using view.annotation
so using the selectedAnnotations
array in there is unnecessary.
Next, openMapsWithItems
expects an array of MKMapItem
objects but in the array you are passing ([selectedLoc, currentLoc]
), selectedLoc
is not an MKMapItem
-- it is just some object that implements MKAnnotation
.
Running this code will result in a crash with this error:
-[MKPointAnnotation dictionaryRepresentation]: unrecognized selector sent to instance
when the Maps app tries to use selectedLoc
as if it was an MKMapItem
.
Instead, you need to create an MKMapItem
from the selectedLoc
annotation. This can be done by first creating an MKPlacemark
from the annotation using MKPlacemark(coordinate:addressDictionary:)
and then creating an MKMapItem
from the placemark using MKMapItem(placemark:)
.
Example:
func mapView(mapView: MKMapView!, annotationView view: MKAnnotationView!,
calloutAccessoryControlTapped control: UIControl!) {
let selectedLoc = view.annotation
println("Annotation '\(selectedLoc.title!)' has been selected")
let currentLocMapItem = MKMapItem.mapItemForCurrentLocation()
let selectedPlacemark = MKPlacemark(coordinate: selectedLoc.coordinate, addressDictionary: nil)
let selectedMapItem = MKMapItem(placemark: selectedPlacemark)
let mapItems = [selectedMapItem, currentLocMapItem]
let launchOptions = [MKLaunchOptionsDirectionsModeKey: MKLaunchOptionsDirectionsModeDriving]
MKMapItem.openMapsWithItems(mapItems, launchOptions:launchOptions)
}