Touching MKMapView causes pins to move slightly

656 views Asked by At

I add a pin where a user touches with this code:

func addPin(tap: UITapGestureRecognizer) {
        if (tap.state == UIGestureRecognizerState.Ended) {
            
            var coordinate = mapView.convertPoint(tap.locationInView(mapView), toCoordinateFromView: mapView)
            
            let address = addressAnnotationLogic.createWithCoordinate(coordinate)
            mapView.addAnnotation(address)
            routeLogic.addAddressAnnotation(address, toRoute: currentRoute!)
            
            // reverse geocode
            let pinLocation = CLLocation(latitude: coordinate.latitude, longitude: coordinate.longitude)
            let geocoder = CLGeocoder()
            
            geocoder.reverseGeocodeLocation(pinLocation!, completionHandler: {
                (placemarks, error) -> Void in

                if error != nil {
                    println("Reverse geocoder failed with error " + error.localizedDescription)
                }
                
                if placemarks.count > 0 {
                    let topResult = placemarks[0] as? CLPlacemark
                    self.addressAnnotationLogic.updateAnnotation(address, withPlacemark: topResult!)
                }
            })
        }
}

My addressAnnotationLogic just creates a backing NSManagedObjectModel to save it, and my routeLogic just adds it to a route which is another NSManagedObjectModel. My delegate methods are pretty standard.

func mapView(mapView: MKMapView!, viewForAnnotation annotation: MKAnnotation!) -> MKAnnotationView! {
    if annotation is AddressAnnotation {
        var annotationView = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "SimplePinIdentifier")
        annotationView.enabled = true
        annotationView.animatesDrop = true
        annotationView.draggable = false
        annotationView.pinColor = MKPinAnnotationColor.Red
        annotationView.canShowCallout = true
        
        return annotationView
    }
    return nil
}

After my first pin is added, if I touch the screen again, for some reason the initial pin moves just the slightest bit which doesn't seem right. It's more frustrating because later I draw an MKPolyline between points and then the pin will move just ever so slightly making the poly line look incorrect. What is this about? Why the pins move just a little bit after already being added to the MKMapView?

1

There are 1 answers

0
Jörn Eyrich On BEST ANSWER

You should probably make the coordinate property in your AddressAnnotation class dynamic.

class AddressAnnotation: NSObject, MKAnnotation {
    var title = ""

    // this works
    dynamic var coordinate: CLLocationCoordinate2D

    // this doesn't
    // var coordinate: CLLocationCoordinate2D

    init(_ coord:CLLocationCoordinate2D)
    {
        coordinate = coord
    }
}

If this doesn't work, please post your code for the AddressAnnotation class and the updateAnnotation method.

Here's what I think happens:

Your annotation first gets the coordinate that is translated from the screen coordinates of your first tap.

Then, in the asynchronous completion handler of your geocoder invocation, your updateAnnotation() method is called.

I assume that you update the coordinate of your AddressAnnotation to the coordinate of the nearest Placemark in there. Unfortunately, the Map View has probably already drawn your Pin at the original location when that update happens.

When the coordinate is updated asynchronously, the Map View does not notice it. Only when it redraws the annotation (prompted by the next tap), it picks up the updated coordinate (so you see the move from the first tap coordinate to the nearest place mark's coordinate).

Now, the Map View is actually trying to be notified of changes in its annotation's coordinates so that it can automatically redraw at the new coordinates. For that it uses a technology called Key-Value-Observing. "Normal" Swift properties don't support that, however. Making them dynamic does.