4
votes

I am working on an app that places a pin at the users current location as well as places pins based on input from the user for locations. The current location annotation is being placed fine, however when trying to place the user's input coordinates, the annotation is not placed. I have added the annotation properly using map.addAnnotation(annotation) for which annotation.coordinate (for New York) is CLLocationCoordinate2D(latitude: 40.713054, longitude: -74.007227999999998). I found that the viewForAnnotation method is not being called and I think this is the reason why the annotation is not being placed (printing the annotation results in nothing). I have a test app that requests input coordinates and it works in placing the annotation. Also in the test app, printing the annotation in viewForPrints out a value.

Below I have pasted some of the code I think is relevant to the issue. Please comment if you need more.

import UIKit
import MapKit
import CoreLocation
class MapVC: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate {



@IBOutlet weak var map: MKMapView!

override func viewDidLoad() {
    super.viewDidLoad()
    map.delegate = self
}

This function below takes the values from another class and converts the coordinates into CLLocationCoordinate2D type. As mentioned above, annotation.coordinate (for New York) yields CLLocationCoordinate2D(latitude: 40.713054, longitude: -74.007227999999998), so add works in saving the coordinates.

    func add(newLocation location_one:[String:Any]) {
        let momentaryLat = (location_one["latitude"] as! NSString).doubleValue
        let momentaryLong = (location_one["longitude"] as! NSString).doubleValue

        let annotation = MKPointAnnotation()
        annotation.title = location_one["title"] as? String
        annotation.coordinate = CLLocationCoordinate2D(latitude: momentaryLat as CLLocationDegrees, longitude: momentaryLong as CLLocationDegrees)



        map.addAnnotation(annotation) //not sure if this adds the annotation!

        self.map.centerCoordinate = annotation.coordinate
    }


func mapView(_ map: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {

    if (annotation is MKUserLocation) {
        return nil
    }

    let identifier = "pinAnnotation"
    var annotationView = map.dequeueReusableAnnotationView(withIdentifier: identifier) as? MKPinAnnotationView

    if annotationView == nil {
        annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: identifier)
        annotationView?.canShowCallout = true

    } else {
        annotationView?.annotation = annotation

    }
    map.showAnnotations(map.annotations, animated: true)
    return annotationView
}
3
"map.addAnnotation(annotation)" is this called in the main thread ?Lory Huz
Is the add method being called at all?Mihai Fratu
@MihaiFratu I used the add method for my code. It is in another viewController like such: map.add(newLocation:location_one). annotation.coordinate in my add method holds the appropriate coordinates. I believe the problem is that my viewForAnnotation is not being called.Kevin

3 Answers

4
votes

First,

func mapView(_ map: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView?

This is a delegate method and is not used for setting the annotations, It simply

  1. Returns the view associated with the specified annotation object, i.e. The annotation view to display for the specified annotation or nil if you want to display a standard annotation view.`

  2. If you do not implement this method, or if you return nil from your implementation for annotations other than the user location annotation, the map view uses a standard pin annotation view.`

Check it out here-

https://developer.apple.com/reference/mapkit/mkmapviewdelegate/1452045-mapview

The addAnnotation() method is enough for adding the default pin annotations. It may not be getting called because you may have called the

func add(newLocation location_one:[String:Any]) from background queue, which calls addAnnotatinon() method inside.

If you are calling add method in some other controller that too on a background queue, may be some completion handlers, then you need to do it explicitly and call the add annotation method on the main thread

DispatchQueue.main.async {
    self.map.addAnnotation(annotation) //Yes!! This method adds the annotations
}

For debugging purposes change your controller to this, even removing the delegates, then also you will get to see the annotations.

import UIKit
import MapKit

class ViewController:  UIViewController{

@IBOutlet weak var map: MKMapView!

      override func viewDidLoad() {
          super.viewDidLoad()
          let annotation = MKPointAnnotation()
          annotation.title = "Test Location"
          annotation.coordinate = CLLocationCoordinate2D(latitude: 40.71304, longitude: -74.0072)
          self.map.addAnnotation(annotation)
      }
}

So do ensure-

  1. The addAnnotation method is called from the main thread
  2. viewForAnnoation method - you use it to provide customisation to the default pin of the annotation.
0
votes

I think there is no need for using this viewForAnnotation function.Simply you can show annotation by giving coordinates for the annotation and put that into map by map.addAnnotation(annotation) function.

0
votes

Firstly, you not call map.showAnnotations in the viewForAnnotation method, because this is called everytime MapKit decides to draw annotation views -- so if there are multiple annotations available, the map will annoyingly relocate itself, which might result in an endless loop (not sure about the last, but I could think of circumstances when this might occur). You should only call map.showAnnotations upon user request (e.g. button press or other selection), to make the map center around those annotations.

Unfortunatly, your code works perfectly; hopefully you did not forget to call add:

override func viewDidLoad() {
    super.viewDidLoad()

    let loc = ["latitude": "40.713054", "longitude":"-74.00722", "title": "nyc"]
    add(newLocation: loc)
}

Here is the result: enter image description here