Why is ViewForAnnotation not called?

M. Black picture M. Black · Mar 27, 2016 · Viewed 7.1k times · Source

I know this question has been asked multiple times, however all of the answers seem slightly different than what is going on in my app.

My understanding is that the viewForAnnotation function is called once the mapView has its delegate set to the ViewController in which it is being displayed AND an annotation is being added to the map when the mapView scrolls so that it shows inside the mapView region.

Currently I have one main viewController (mainVC) that contains one MKMapView (mapView) This viewController controls four different maps to be displayed in mapView.

func moveViews(sender:Int) {
    // This function handles which button on the Segmented Control was clicked and the loads the appropriate map into the mapView (passed as a para

    removeAnnotationsAndOverlays() // ~~~
    if sender == 0 {
        // First Map was selected
        let map1VC = map1VC()
        map1VC.loadMap1View(mapView)
        map1VC.centerMapOnLocation()
    }
    else if sender == 1 {
        // Second Map was selected
        let map2VC = map2VC()
        map2VC.loadMap2View(mapView)
    }
    else if sender == 2 {
        // Third Map was selected
        let map3VC = map3VC()
        map3VC.loadMap3View(mapView)
    }
    else if sender == 3 {
        // Fourth Map was selected
        let map4VC = map4VC()
        map4VC.loadMap4View(mapView)
    }
    else {
        // Load First Map as default
        let map1VC = map1VC()
        map1VC.loadMap1View(mapView)
        map1VC.centerMapOnLocation()
    }
}

There are several different classes which controls the functionality of each of the different maps:

  1. Map 1 - Displays a combination of MKPolylines and Custom Annotations (inherits from MKAnnotation) that are read from a plist - This works great!
  2. Map 2 - Displays several MKPolylines read from a plist - This works great!
  3. Map 3 - Displays several MKPolylines read from a plist - This works great!
  4. Map 4 - Should display several Custom Annotations - this is NOT WORKING!

Here is what is happening with Map 4:

  • the MKMapView is being loaded properly

    var mapView: MKMapView = MKMapView() // declared as a global variable/object inside the map4VC()
    
    // Initial function to set up Map
    //      Think of this function as the "override func viewDidLoad() {}"
    func loadMap4View(mV: MKMapView) {
    
    // This connects the parameter passed (mV) and sets it as the delegate for the mapView used throughout this file
    //      In other words, it allows the mapView on the MainVC to use all of the code in this file to handle different actions
    mapView = mV
    mapView.delegate = self
    
    let initialLocation = CLLocation(latitude: 50.3603125, longitude: 2.794017)
    
    // calculates the region you'll look at on the screen 
    let coordinateRegion = MKCoordinateRegionMakeWithDistance(initialLocation.coordinate, regionRadius, regionRadius)
    
    // sets the region of the map
    mapView.setRegion(coordinateRegion, animated: true)
    
    
    //addPins()  // This can use a custom function to load all of the Pins
    //mapView.addAnnotations(coords.allLocations!) // This line also works to add all of the individual pins
    
    mapView.addAnnotation(coords.allLocations![2]) // This adds one single Pin
    

    }

  • set the mapView's delegate to the current class (mapView.delegate = self)

  • it zooms in on the proper location (mapView.setRegion(coordinateRegion, animated: true))
  • the class reads from a plist and (using a helper class) builds an array of custom MKAnnotations (CemAnno)

  • The locations are stored in an array of CemAnno's called allLocations:

    var allLocations: [CemAnno]? = [] // This is declared in the helper class along with a bunch of other stuff that grabs all of the information from a plist
    
     class CemAnno: NSObject, MKAnnotation {
    
    var coordinate: CLLocationCoordinate2D
    var title: String?
    var casualties: String?
    var visitInfo: String?
    var histInfo: String?
    var region: String?
    
    
    init(title: String, coordinate: CLLocationCoordinate2D, region: String, casualties: String, visitInfo: String, histInfo: String) {
    
    self.coordinate = coordinate
    self.title = title
    self.region = region
    self.casualties = casualties
    self.visitInfo = visitInfo
    self.histInfo = histInfo
    }
    

    }

    // This builds an object inside the the map4VC() class called coords that holds all of the information collected from the plist
    var coords = BuildCoordinates(filename: "Coordinate")
    
  • adds each one of these to the map (mapView.addAnnotations) and they are displayed as pins (they are being displayed) mapView.addAnnotation(coords.allLocations![2]) // This adds one single Pin Annotation (which works) but never calls the viewForAnnotation function

This works, however, I'm trying to customize the annotations that are being displayed but the ViewForAnnotation function is never called????

// This function is NEVER called
func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView?
{
    // Define a reuse identifier. This is a string that will be used to ensure we reuse annotation views as much as possible.
    let identifier = "CemAnno"

    // Check whether the annotation we're creating a view for is one of our CemAnno objects.
    if annotation.isKindOfClass(CemAnno.self) {
        print("correct class")
        //let anno = annotation as! CustomAnnotation
        // Try to dequeue an annotation view from the map view's pool of unused views.
        var annotationView = mapView.dequeueReusableAnnotationViewWithIdentifier(identifier)

        if annotationView == nil {
            print("no reusable view")
            // If it isn't able to find a reusable view, create a new one using MKPinAnnotationView and sets its canShowCallout property to be true. This triggers the popup with the name.
            annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
            annotationView!.canShowCallout = true

            // Create a new UIButton using the built-in .Custom type. This is so we can add an image to the button.
            let btn = UIButton(type: .DetailDisclosure)
            //btn.setImage(anno.image, forState: .Normal)
            annotationView!.rightCalloutAccessoryView = btn
        } else {
            print("reusing a view")
            // If it can reuse a view, update that view to use a different annotation.
            annotationView!.annotation = annotation
        }

        return annotationView

    }

    // If the annotation isn't from a CustomClass, it must return nil so iOS uses a default view.
    return MKPinAnnotationView()
}

I've tried adding the location of a pin inside the current view region of the map but the ViewForAnnotation is never fired. I've tried adding the location of the pin outside of the current view region of the map but the ViewForAnnotation is never fired - I figured this should be the one that works, and as I 'scroll' the map and it shows up inside the current view region that should fire the function, but it doesn't (I should note that the pin is being displayed and shows up on the map).

This makes it so that I cannot customize the pin which I would like to do.

I'm using the same technique as Map 1 which works perfectly fine, but for some reason the ViewForAnnotation is never called inside Map 4.

Any suggestions would be greatly appreciated!!

Answer

wj2061 picture wj2061 · Apr 4, 2016

I encountered this problem from time to time.And I found that sometimes you need to call showAnnotations:animated: manually like this :

mapView.showAnnotations(mapView.annotations, animated: true)