Search code examples
iosswiftmkannotation

Multiple annotations giving the same details when pressed


I have multiple annotations all working correctly and showing everything I want them to. However I want to display a detail view when the annotation callout accessory is pressed. I have it all working to the point where the details passed into the calloutAccessoryControlTapped function, which are only last to be loaded at run time and not of the annotation pressed.

I have scoured the internet for an answer to this and can't seem to find the solution.

Please help!!

P.S. Please excuse the code being messy at some points, I've been messing about with it, A LOT!!

class SecondViewController: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {

class CustomPointAnnotation: MKPointAnnotation {

    var imageName: String!
    var ID: String!

}


@IBOutlet weak var mapSeg: UISegmentedControl!
@IBOutlet weak var mainMapView: MKMapView!

@IBOutlet weak var webView: UIWebView!

var manager = CLLocationManager()
let signalsArray = ["MC 411 Signal", "MC 413 Signal ", "MC 414 Signal","MC 415 Signal", "MC 416 Signal", "MC 417 Signal", "MC 434 Signal", "MC 436 Signal", "MC 438 Signal"]
var segueIdentity: String?

override func viewDidLoad() {
    super.viewDidLoad()

    println("screen loaded")

    mainMapView.delegate = self


   loadUrl()



    var latitude:CLLocationDegrees = 55.691203
    var longitude:CLLocationDegrees = -3.668746

    var latDelta:CLLocationDegrees = 0.002  //zoom level, smaller = closer
    var lonDelta:CLLocationDegrees = 0.002


    var span:MKCoordinateSpan = MKCoordinateSpanMake(latDelta, lonDelta)
    var location:CLLocationCoordinate2D = CLLocationCoordinate2DMake(latitude, longitude)
    var region:MKCoordinateRegion = MKCoordinateRegionMake(location, span)
    var station = CustomPointAnnotation()

    mainMapView.mapType = MKMapType.Hybrid
    mainMapView.setRegion(region, animated: true)


    mainMapView.frame = CGRectMake(19, 72, 984, 321)
    webView.frame = CGRectMake(12, 397, 999, 321)


    //add a pin to the location
    station.coordinate = location
    station.title = "Carstairs Train Station"
    station.subtitle = "Motherwell Panel 6"
    station.imageName = "devil"
    station.ID = "station"
    mainMapView.addAnnotation(station)




    var sig1 = CustomPointAnnotation()
    var sig1Location:CLLocationCoordinate2D = CLLocationCoordinate2DMake(55.690905, -3.66723)

    sig1.coordinate = sig1Location
    sig1.title = signalsArray [2]//MC414
    sig1.subtitle = "Caution, short signal section to MC 434"
    sig1.imageName = "GRS"
    sig1.ID = "sig1"

    mainMapView.addAnnotation(sig1)


    var sig2 = CustomPointAnnotation()
    var sig2Location:CLLocationCoordinate2D = CLLocationCoordinate2DMake(55.688745, -3.662528)

    sig2.coordinate = sig2Location

    sig2.title = signalsArray [6]//MC434
    //sig2.subtitle = ""
    sig2.imageName = "devil"
    sig2.ID = "sig2"
    mainMapView.addAnnotation(sig2)



    var sig3 = CustomPointAnnotation()
    var sig3Location:CLLocationCoordinate2D = CLLocationCoordinate2DMake(55.691119, -3.668915)

    sig3.coordinate = sig3Location

    sig3.title = signalsArray [3]//MC415
    //sig3.subtitle = ""
    sig3.imageName = "GRS"
    sig3.ID = "sig3"
    mainMapView.addAnnotation(sig3)



    var sig4 = CustomPointAnnotation()
    var sig4Location:CLLocationCoordinate2D = CLLocationCoordinate2DMake(55.691087, -3.668950)

    sig4.coordinate = sig4Location

    sig4.title = signalsArray [5]//MC417
    //sig4.subtitle = ""
    sig4.imageName = "GRS"
    sig4.ID = "sig4"
    mainMapView.addAnnotation(sig4)



    var sig5 = CustomPointAnnotation()
    var sig5Location:CLLocationCoordinate2D = CLLocationCoordinate2DMake(55.690856, -3.667783)

    sig5.coordinate = sig5Location

    sig5.title = signalsArray [4]//MC416
    //sig5.subtitle = ""
    sig5.imageName = "GRS"
    sig5.ID = "sig5"
    mainMapView.addAnnotation(sig5)



}

//Add a picture and button to annotation pin
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView!{

    if !(annotation is CustomPointAnnotation){

        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!.animatesDrop = true
        pinView!.pinColor = MKPinAnnotationColor.Purple

        pinView!.rightCalloutAccessoryView = UIButton.buttonWithType(UIButtonType.DetailDisclosure) as UIButton


    }else {


    }

    let cpa = annotation as CustomPointAnnotation

    var imageview = UIImageView(frame: CGRectMake(0, 0, 45, 45))
    var segueId = cpa.ID

    pinView!.leftCalloutAccessoryView = imageview
    imageview.image = UIImage(named: cpa.imageName)

    println(segueId)
    segueIdentity = segueId

    return pinView
}


func mapView(mapView: MKMapView!, annotationView: MKAnnotationView!, calloutAccessoryControlTapped control: UIControl!) {


    if control == annotationView.rightCalloutAccessoryView {

        println("Right accessory pressed with " + segueIdentity!)


       pinSelected()


    }
}

func mapView(mapView: MKMapView!, didDeselectAnnotationView view: MKPointAnnotation) {


    println("selected annotation = " + segueIdentity!)
}



func pinSelected(){

    UIView .animateWithDuration(0.5, animations: {

        self.mainMapView.frame = CGRectMake(19, 72, 984, 595)
        self.webView.frame = CGRectMake(12, 670, 999, 50)

    })

    println("pinselected fired with " + (segueIdentity)!)

    self.performSegueWithIdentifier("pinSegue", sender: self)


}


override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {


    if (segue.identifier == "pinSegue"){

        println("prepare for segue fired! with " + (segueIdentity)!)

        /*CustomPointAnnotation annotationView = sender
        segue.destinationViewController setAnnotation*/

    }
}

Solution

    1. A number of your delegate methods are referencing segueIdentity, which you set in viewForAnnotation. You should not be referencing these class properties in order to know which annotation was tapped.

      You should instead determine the appropriate annotation by taking the annotation view passed to you, look at the annotation property, and then access your custom annotation's properties (e.g. the ID property) at that point.

      func mapView(mapView: MKMapView!, annotationView view: MKAnnotationView!, calloutAccessoryControlTapped control: UIControl!) {
          if let annotation = view.annotation as? CustomPointAnnotation {
              let identifier = annotation.ID
      
              // now use `identifier` here, not `segueIdentity`
          }
      }
      

      Frankly, I'd be inclined to retire the segueIdentity property entirely.

    2. Your if pinView == nil needs and else clause, or else the recycled annotation view will continue to reference the old annotation, e.g.

      if pinView == nil {
          pinView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: reuseId)
          pinView!.canShowCallout = true
          pinView!.animatesDrop = true
          pinView!.pinColor = MKPinAnnotationColor.Purple
      
          pinView!.rightCalloutAccessoryView = UIButton.buttonWithType(UIButtonType.DetailDisclosure) as UIButton
      } else {
          pinView!.annotation = annotation
      }