在Swift 2中:无法触发calloutAccessoryControlTapped以获取地图注释上的点击

时间:2015-10-03 17:20:02

标签: ios swift core-data annotations mapkit

我正在开发一个人项目,允许用户在地图上添加注释引脚,然后从Flickr下载所选位置的照片。引脚/注释是可点击的,以便触发某些功能(例如,删除或触发到详细视图的segue)。我目前无意中使callout action工作。以下是我写的代码:

class ViewController: UIViewController {

    @IBOutlet weak var mapView: MKMapView!

    let reusedPinId = "pin"
    var selectedLocation: TouringLocationAnnotation!
    let initLocation = CLLocation(latitude: 21.282788, longitude: -157.829444)
    let regionRadius: CLLocationDistance = 1000
    var myPin: MKPinAnnotationView?
    var editModeOn = false


    override func viewDidLoad() {
        super.viewDidLoad()
        let longPressRecognizer = UILongPressGestureRecognizer()
        longPressRecognizer.addTarget(self, action: "addMapAnnotation:")
        mapView.addGestureRecognizer(longPressRecognizer)
        mapView.delegate = self
        centerMapOnLocation(initLocation)

        let touringSpot = TouringSpot(title: "Picture at this touring site", coordinate: CLLocationCoordinate2D(latitude: 21.283921, longitude: -157.831661))
        mapView.addAnnotation(touringSpot) //TODO: change this to the first pin
        self.navigationItem.rightBarButtonItem = self.editButtonItem() //toggle edit and Done
        self.navigationItem.title = "Virtual Tourist"

        fetchedResultsController.delegate = self

        do {
            try fetchedResultsController.performFetch()

            if let savedPins = fetchedResultsController.fetchedObjects {
                for pin in savedPins {
                    print("retrieved a pin from coredata")
                    showPinOnMap(pin as! Pin)
                }
            }
        } catch let error as NSError {
            print("error in retrieving saved pins: \(error)")
        }

    }

//show the pin as an annotation on map
    func showPinOnMap(pin: Pin) {
        if pin.isValid() { //check if the pin has coordinate set up
            let locationAnnot = TouringLocationAnnotation(tourLocationPin: pin)
            //TODO: fetch photo for the pin
            if pin.photos.count == 0 {
                print("about to fetch flickr photos for pin:")
                pin.fetchPhotosFromFlickr({ (success, error) -> Void in
                    if success {
                        print("successfl in fetching flickr photos")
                    } else {
                        print("error in fetching flickr photos")
                        //TODO: give warning to user
                        return
                    }
                });
            }
            mapView.addAnnotation(locationAnnot)
        } else {
            print("pin is invalid")
            //TODO: give warning to user on invalid pin
        }
    }


    func centerMapOnLocation(location: CLLocation) {
        let coordinateRegion = MKCoordinateRegionMakeWithDistance(location.coordinate, regionRadius * 2.0, regionRadius * 2.0)
        mapView.setRegion(coordinateRegion, animated: true)
    }
}

以下是添加地图注释的方法:

func centerMapOnLocation(location: CLLocation) {
        let coordinateRegion = MKCoordinateRegionMakeWithDistance(location.coordinate, regionRadius * 2.0, regionRadius * 2.0)
        mapView.setRegion(coordinateRegion, animated: true)
    }


    func addMapAnnotation(gestureRecognizer: UIGestureRecognizer) {
        if gestureRecognizer.state == UIGestureRecognizerState.Began {
            let touchPoint = gestureRecognizer.locationInView(mapView)
            let newCoordinate = mapView.convertPoint(touchPoint, toCoordinateFromView: mapView)
            let annotation = TouringSpot(title: "new spot", coordinate: newCoordinate)
            var locationNameStr = ""
            let locationDictionary: [String:AnyObject] = [
                Pin.Keys.Name: "\(newCoordinate.latitude, newCoordinate.longitude)",
                Pin.Keys.Latitude: newCoordinate.latitude,
                Pin.Keys.Longitude: newCoordinate.longitude
            ]
            defer {
                //TODO: check for duplicate pins in database first?
                let newPin = Pin(dictionary: locationDictionary, context: sharedContext)
                newPin.name = locationNameStr

                do {
                //persist the new pin to core data
                    try sharedContext.save()
                    print("saved a pin!")
                    showPinOnMap(newPin)
                } catch let error as NSError {
                    print("error saving the new pin in context")
                }
            }


            //problem: cannot pass the locationNameStr to the defer{} block
            //TODO: retrieve the location name as title of the annotation
            CLGeocoder().reverseGeocodeLocation(CLLocation(latitude: newCoordinate.latitude, longitude: newCoordinate.longitude), completionHandler: {(placemarks, error) -> Void in

                if error != nil {
                    print("reverse geocoding failed with error: \(error)")
                    //return
                } else if placemarks!.count > 0 {
                    let firstPlace = placemarks![0] as CLPlacemark

                    if firstPlace.country != nil {
                        locationNameStr = "a place in \(firstPlace.country!)"
                    }
                    else if firstPlace.locality != nil {
                        locationNameStr = "a place in \(firstPlace.locality!)"
                    }
                    print("location name: \(locationNameStr)")
                }
            })

        }
    }

点击“编辑”按钮后,用户可以点击图钉进行删除:

override func setEditing(editing: Bool, animated: Bool) {
        super.setEditing(editing, animated: animated)

        if editing {
            print("going to edit the pins")

            let titleDict: NSDictionary = [NSForegroundColorAttributeName: UIColor.redColor()
            ]
            navigationController?.navigationBar.titleTextAttributes = titleDict as! [String : AnyObject]

            self.navigationItem.title = "Click a pin for deletion"
            editModeOn = true
        } else {
            print("done with editing the pins")
            let titleDict: NSDictionary = [NSForegroundColorAttributeName: UIColor.blackColor()
            ]
            navigationController?.navigationBar.titleTextAttributes = titleDict as! [String : AnyObject]
            self.navigationItem.title = "Tourist"
            editModeOn = false
        }
    }

以下是我对MKMapViewDelegate

的实施情况
extension ViewController: MKMapViewDelegate {

    func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {

        if let anno = annotation as? TouringLocationAnnotation {
            print("calling the viewForAnnotation delegate")
            var pinView: MKPinAnnotationView!
            if let dequeuedView = mapView.dequeueReusableAnnotationViewWithIdentifier(reusedPinId)
                as? MKPinAnnotationView {
                    dequeuedView.annotation = anno
                    pinView = dequeuedView
            } else {
                pinView = MKPinAnnotationView(annotation: anno, reuseIdentifier: reusedPinId)

            }
            pinView.canShowCallout = true
            if #available(iOS 9.0, *) {
                pinView.pinTintColor = UIColor.purpleColor()
            } else {
                // Fallback on earlier versions
            }
            pinView.animatesDrop = true
            // pinView.calloutOffset = CGPoint(x: -5, y: 5)

            let btn = UIButton(type: .DetailDisclosure)
            // btn.addTarget(self, action: Selector("showPhotosForPin:"), forControlEvents: UIControlEvents.TouchUpInside)

            pinView.rightCalloutAccessoryView = btn //UIButton.buttonWithType(.DetailDisclosure) as! UIView
            return pinView
        }
        return nil
    }

    //call out
    func mapView(mapView: MKMapView!, annotationView view: MKAnnotationView!, calloutAccessoryControlTapped control: UIControl!) {
        print("callout accessory control triggered!")
        /*
        if let annotation = view.annotation as? TouringLocationAnnotation {
            mapView.removeAnnotation(annotation)
        }
        */
        let annotation = view.annotation as! TouringLocationAnnotation
        if control == view.rightCalloutAccessoryView {
            print("right callout button is clicked")
        }
    }


    func showPhotosForPin(sender: UIButton!) {
        print("showing photos for pin")
    }


    func mapView(mapView: MKMapView, didSelectAnnotationView view: MKAnnotationView) {
        let latitude = view.annotation!.coordinate.latitude
        let longitude = view.annotation!.coordinate.longitude
        //let annotation = view.annotation as! TouringLocationAnnotation

        if !editModeOn {
            print("did select the annotation View, getting its coordinates, latitude: \(latitude), longitude: \(longitude)")
            // print("pin is: \(annotation.tourLocationPin.latitude)")
        } else {
            print("for deleting the pin")
        }
    }    
}

引脚保留在CoreData中,当应用程序启动时,它们将从持久性中获取并在地图上注释。从下面的屏幕截图中可以看出,这些引脚是用紫色标注的(唯一的红色引脚来自我的硬编码注释,而不是来自CoreData),我认为这表明我的引脚被转换为{{1} }成功输入。但是,当我点击引脚时,标注动作不会触发,我希望看到以下打印输出

MKAnnotationView

请注意,为简洁起见,我们省略了CoreData的代码,因为我认为它们与我的问题无关

enter image description here

1 个答案:

答案 0 :(得分:1)

我认为你的代码是正确的。它对我来说很好。

enter image description here

enter image description here

我有点好奇。

  

但是,当我点击引脚时,不会触发标注操作,

单击图钉时,不会调用calloutAccessoryControlTapped

当您在引脚上单击UIButton时,会调用calloutAccessoryControlTapped