Have a custom MKClusterAnnotation named 'ClusterAnnotationView.' It is failing at 'assertionFailure' message when I'm not expecting it.
Here is the code:
//MARK: CLUSTER ANNOTATION
final class ClusterAnnotationView: MKAnnotationView {
override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
collisionMode = .circle
displayPriority = .defaultHigh
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override var annotation: MKAnnotation? {
didSet {
guard let annotation = annotation as? MKClusterAnnotation else {
print(annotation)
assertionFailure("Using ClusterAnnotationView with wrong annotation type")
return
}
self.image = image(count: annotation.memberAnnotations.count)
}
}
private func image(count: Int) -> UIImage {
let bounds = CGRect(origin: .zero, size: CGSize(width: 40, height: 40))
let renderer = UIGraphicsImageRenderer(bounds: bounds)
return renderer.image { _ in
//background
Definitions.Colors.Water.setFill()
UIBezierPath(ovalIn: bounds).fill()
// Fill inner circle with white color inset so background shows as border
UIColor.white.setFill()
UIBezierPath(ovalIn: bounds.insetBy(dx: 4, dy: 4)).fill()
// Finally draw count text vertically and horizontally centered
let attributes: [NSAttributedString.Key: Any] = [
.foregroundColor: UIColor.black,
.font: UIFont.boldSystemFont(ofSize: 14)
]
let text = "\(count)"
let size = text.size(withAttributes: attributes)
let origin = CGPoint(x: bounds.midX - size.width / 2, y: bounds.midY - size.height / 2)
let rect = CGRect(origin: origin, size: size)
text.draw(in: rect, withAttributes: attributes)
}
}
}
Now if I comment out the 'assertionFailure("Using ClusterAnnotationView with wrong annotation type")' it'll shown the clustered annotations with the correct number. The print of annotations all print nil.
Reviewed the docs on Apple on Clustering and quite a few others. Many examples show it like I have it.
It's registered
mapView.register(ClusterAnnotationView.self, forAnnotationViewWithReuseIdentifier: MKMapViewDefaultClusterAnnotationViewReuseIdentifier)
and the delegate for it is like so
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
switch annotation {
case is MapAnnotation:
let eventAnnotation = MapAnnotationView(annotation: annotation, reuseIdentifier: MKMapViewDefaultAnnotationViewReuseIdentifier)
eventAnnotation.delegate = self
return eventAnnotation
case is MKClusterAnnotation:
//return ClusterAnnotationView(annotation: annotation, reuseIdentifier: MKMapViewDefaultClusterAnnotationViewReuseIdentifier)
return mapView.dequeueReusableAnnotationView(withIdentifier: MKMapViewDefaultClusterAnnotationViewReuseIdentifier, for: annotation)
default:
return nil
}
}
I've tried the return in the delegate with both the class and just the dequeue with same results.
Something odd is happening because the clustered annotations causes the maps functionality to be really laggy and it's possibly related to the problem I'm seeing.
Anyone have any insights?
Thanks
There is at least one mistake in
func mapView
:You need a different reuseIdentifier for each different
MKAnnotationView
subclass for which you are callingmapView.dequeueReusableAnnotationView
.What happens here is random:
if
return mapView.dequeueReusableAnnotationView
is called first, it returns nil.nil means
mapView.register...
kicks in and creates aClusterAnnotationView
instance and everything works fine. That's when you see numbers.It gets interesting once you created several
MapAnnotationView
and the first is thrown away when it isn't displayed any more:Since you use the same
reuseIdentifier
,will return an object of type
MapAnnotationView
.Also, after using
dequeue...
you should set the annotation of the dequeuedMKMarkerAnnotaionView
subclass object.This is the pattern you use for each different annotation type:
You might do a similar pattern for MapAnnotationView.
It is always the same: you try to dequeue. If it fails, you create a new one. For each different
MKMarkerAnnotaionView
subclass, you use a differentreuseIdentifier
.