According to this post whenever you call addAnnotation
method, mapView:viewForAnnotation
gets called
However the following code called mapView:viewForAnnotation
only once. I have several annotations, but "view called" was only printed once. I guess this has something to do with the thread?
import UIKit
import MapKit
import CoreLocation
class ViewController: UIViewController, UITextFieldDelegate, MKMapViewDelegate, CLLocationManagerDelegate {
@IBOutlet var searchtext: UITextField!
@IBOutlet var map: MKMapView!
var locationManager = CLLocationManager()
override func viewDidLoad() {
super.viewDidLoad()
self.searchtext.delegate = self
locationManager.delegate = self
self.map.delegate = self
locationManager.desiredAccuracy = kCLLocationAccuracyBest
locationManager.requestWhenInUseAuthorization()
locationManager.startUpdatingLocation()
}
func textFieldDidBeginEditing(textField: UITextField!) { //delegate method
var allAnnotations = self.map.annotations
self.map.removeAnnotations(allAnnotations)
}
func textFieldShouldReturn(textField: UITextField!) ->Bool {
textField.resignFirstResponder()
//...
let session = NSURLSession.sharedSession()
var task = session.dataTaskWithURL(url!, completionHandler: { (date, response, error) -> Void in
if (error != nil) {
println(error)
}else {
var placenum = 0
//placenum is to see if all the places are in the visible rect. If so I will use showAnnotations to zoom (in) to the best-fitted view show them. If not, I will only show these in the visible rect
for place in places {
//...
if (regionContains(self.map.region, coordinate)) {
placenum = placenum+1
}
self.map.addAnnotation(annotation)
}
if (placenum==places.count) {
self.map.showAnnotations(self.map.annotations, animated: true)
}
}
})
task.resume()
return true
}
func locationManager(manager: CLLocationManager!, didUpdateLocations locations: [AnyObject]!) {
//...
self.map.setRegion(region, animated: false)
locationManager.stopUpdatingLocation()
}
func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
println("view called")
return nil
}
In short, mapView(_:viewFor:)
is called when an annotation falls within the visible portion of the map view. Namely, either (a) an annotation has been added to a map view and it falls with the region
or (b) the region
changes such that an annotation that was not previously visible now is. Needless to say, this method also will only be called if you set the delegate of the map view (either programmatically or in Interface Builder).
By the way, the completion handler of dataTask(with:completionHandler:)
will not be called on the main thread. Thus, any UI updates must be explicitly dispatched back to the main thread, e.g.
DispatchQueue.main.async {
for place in places {
//...
placenum = placenum + 1
self.map.addAnnotation(annotation)
}
self.map.showAnnotations(self.map.annotations, animated: true)
}
I would recommend ensuring that interaction with the map view happens on the main thread, as shown above.
By the way, remember that if you're showing the user location on the map, that, itself, results in mapView(_:viewFor:)
being called. So if you're seeing it called only once, you might want to confirm whether the annotation
is a MKUserLocation
or one of the annotations you added.