MKMarkerAnnotationView 错误,由于未捕获的异常而终止应用程序

MKMarkerAnnotationView Error, Terminating app due to uncaught exception

enter image description here

在地图上显示标注时,可以构建并执行,但是执行过程中出错,停止了。 MKMarkerAnnotationView 显示聚类和字形图像。 大约有100个注解,在加载View的时候从Firestore获取并存储在一个数组中。 放大或移动地图时发生错误。 Swift 版本:Swift5 我也检查了插座连接,但看起来没有问题。

找不到解决办法,你能告诉我哪里出了问题吗? 写了Map等的设置方法,如果从根本上说错了,还望指教

错误 [XXX.CustomPinAnnotation memberAnnotations]:无法识别的选择器发送到实例 0x2835e16c0

CustomPinAnnotation.swift


import UIKit
import MapKit

class CustomPinAnnotation: NSObject, MKAnnotation {

    let clusteringIdentifier : String
    let title: String?
    let subtitle: String?
    let coordinate: CLLocationCoordinate2D
    //let glyphText: String
    let glyphImage: UIImage
    let glyphTintColor: UIColor
    let markerTintColor: UIColor
    let objectid: Int

    init(_ clusteringIdentifier: String, title: String, subtitle: String, coordinate: CLLocationCoordinate2D, glyphImage: UIImage, glyphTintColor: UIColor, markerTintColor: UIColor, objectid: Int) {
        self.clusteringIdentifier = clusteringIdentifier
        self.title = title
        self.subtitle = subtitle
        self.coordinate = coordinate
//        self.glyphText = glyphText
        self.glyphImage = glyphImage
        self.glyphTintColor = glyphTintColor
        self.markerTintColor = markerTintColor
        self.objectid = objectid
    }
}

ViewController.swift

import UIKit
import MapKit
import CoreLocation

class ViewController: UIViewController, CLLocationManagerDelegate, MKMapViewDelegate {

    var locationManager = CLLocationManager()
    var userCoordinate = CLLocationCoordinate2D()

    //object array
    var objectAll = [objectData]()        

    //Map view
    @IBOutlet weak var mapView: MKMapView!

    func displayAllMountains() {
        for mountain in objectAll {
            let pinImage = UIImage.init(named: "XXXXX")!
            let subtitletext = String(object.height) + "m"
            let annotation = CustomPinAnnotation("clusterid", title:object.name, subtitle: subtitletext, coordinate: object.geopoint, glyphImage: pinImage, glyphTintColor: .white, markerTintColor: .darkGray, objectid: object.objectid)                        
            self.mapView.addAnnotation(annotation)
        }
    }

    func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {   
        if annotation === mapView.userLocation {
            return nil
        } else {
            let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: MKMapViewDefaultAnnotationViewReuseIdentifier, for: annotation)

            guard let markerAnnotationView = annotationView as? MKMarkerAnnotationView,
                let annotation = annotation as? CustomPinAnnotation else {
                     return annotationView
            }

            markerAnnotationView.clusteringIdentifier = annotation.clusteringIdentifier
//            markerAnnotationView.glyphText = annotation.glyphText
            markerAnnotationView.glyphImage = annotation.glyphImage
            markerAnnotationView.glyphTintColor = annotation.glyphTintColor
            markerAnnotationView.markerTintColor = annotation.markerTintColor
            return markerAnnotationView
        }
    }
}

你说它在报告:

Error [XXX.CustomPinAnnotation memberAnnotations]: unrecognized selector sent to instance 0x2835e16c0

memberAnnotations 是一种 MKClusterAnnotation 方法。但它试图在您的 CustomPinAnnotation 对象上调用该方法。在某个地方,它试图在预期 MKClusterAnnotation.

的上下文中使用 CustomPinAnnotation

我无法证明你的问题,我不确定你分享的内容是否足够让我们重现它。但我很容易看出它是如何混淆的。注释类型有三种,不仅有MKUserLocationCustomPinAnnotation,还有MKClusterAnnotation。您的 mapView(_:viewFor:) 只考虑了前两种类型的存在。如果需要,您也可以让它处理 MKClusterAnnotation

func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
    if annotation is MKUserLocation {
        return nil
    } else if annotation is MKClusterAnnotation {
        return mapView.dequeueReusableAnnotationView(withIdentifier: MKMapViewDefaultClusterAnnotationViewReuseIdentifier, for: annotation)
    }

    let annotationView = mapView.dequeueReusableAnnotationView(withIdentifier: MKMapViewDefaultAnnotationViewReuseIdentifier, for: annotation)

    guard
        let markerAnnotationView = annotationView as? MKMarkerAnnotationView,
        let annotation = annotation as? CustomPinAnnotation
    else {
        return annotationView
    }

    markerAnnotationView.clusteringIdentifier = annotation.clusteringIdentifier
    markerAnnotationView.displayPriority = .required
    // markerAnnotationView.glyphText = annotation.glyphText
    markerAnnotationView.glyphImage = annotation.glyphImage
    markerAnnotationView.glyphTintColor = annotation.glyphTintColor
    markerAnnotationView.markerTintColor = annotation.markerTintColor
    return markerAnnotationView
}

不过,就我个人而言,我建议完全删除 mapView(_:viewFor:),而是定义您自己的注释视图 class 来执行此配置:

class CustomAnnotationView: MKMarkerAnnotationView {
    override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
        super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
        update(for: annotation)
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override var annotation: MKAnnotation? { didSet { update(for: annotation) } }
    
    func update(for annotation: MKAnnotation?) {
        displayPriority = .required

        guard let annotation = annotation as? CustomPinAnnotation else { return }
        
        clusteringIdentifier = annotation.clusteringIdentifier
        // markerAnnotationView.glyphText = annotation.glyphText
        glyphImage = annotation.glyphImage
        glyphTintColor = annotation.glyphTintColor
        markerTintColor = annotation.markerTintColor
    }
}

当然,请务必注册它(以及您的集群注释视图):

mapView.register(CustomAnnotationView.self, forAnnotationViewWithReuseIdentifier: MKMapViewDefaultAnnotationViewReuseIdentifier)
mapView.register(MKMarkerAnnotationView.self, forAnnotationViewWithReuseIdentifier: MKMapViewDefaultClusterAnnotationViewReuseIdentifier)

但关键是 mapView(_:viewFor:) 的默认实现会自动处理所有三种类型的注释视图。通过这种方式,我们将坚韧不拔的“我如何呈现此注释视图”代码从视图控制器(或任何 MKMapViewDelegate 是)中取出并放入它所属的注释视图 class 中。