I have an app with a map section displaying devices. In some cases devices may be either really close to each other or even have exactly the same coordinates. In order to display it I use default clustering mechanism in MapKit.
func mapView(_ mapView: MKMapView, clusterAnnotationForMemberAnnotations memberAnnotations: [MKAnnotation]) -> MKClusterAnnotation {
return MKClusterAnnotation(memberAnnotations: memberAnnotations)
}
When user taps on cluster annotation, the app supposed to zoom in maximally and then in case of cluster still existing on map (member annotations are too close to be presented separately) open custom view describing cluster objects.
To achieve that, I have few custom functions, their implementation contains only standard calls setRegion or setVisibleMapRect.
setRegionCovering(_ annotations: [MKAnnotation], on mapView: MKMapView)
getZoom(delta: CGFloat)
func mapView(_ mapView: MKMapView, didSelect view: MKAnnotationView) {
if let annot = view.annotation as? MKClusterAnnotation {
let clusteredAnnotations = annot.memberAnnotations as? [CustomAnnotation] ?? []
let currentZoom = mapView.getZoom(delta: CGFloat(mapView.region.span.longitudeDelta))
guard currentZoom == self.maxZoom else {
self.setRegionCovering(clusteredAnnotations, on: mapView)
return
}
self.delegate?.drawCluster(annotations: clusteredAnnotations)
}
}
In order to invoke cluster after zooming in I use regionDidChangeAnimated method:
func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
if let activeCluster = mapView.selectedAnnotations.first(where: { $0.isKind(of: MKClusterAnnotation.self)}) as? MKClusterAnnotation {
self.delegate?.drawCluster(annotations: activeCluster.memberAnnotations as? [CustomAnnotation] ?? [])
}
}
Everything so far works as expected, except one thing - regionDidChangeAnimated is called after camera focus (region) is finalized. However, I found out that in some cases clustering continues after regionDidChangeAnimated was called. Because of that, in some rare cases after tapping Cluster annotation user will see a short 'blink' of cluster contents and then it will disappear as well as an old cluster, replaced by smaller clusters or member annotations.
Earlier I've tried to do the same by embedding map zooming actions inside of animate function in order to handle cluster view opening in completion.
MKMapView.animate(withDuration: 1.0, animations: {}, completion: { _ in })
But found out that completion fires before regionDidChangeAnimated and is even more inaccurate. Afterwards I have also found out Apple is strongly encouraging against completions when working with map.
Any ideas what I'm doing wrong or how can I solve this?