With SwiftUI, I add 5 000 annotations to MKMapView
. When the map is moved round, zoomed in or out, the app is lagging.
What I’ve completed to extend efficiency is:
- Set
.clusteringIdentifier
onMKMarkerAnnotationView
- Set
reuseIdentifier
onMKMarkerAnnotationView
- Dequeue
MKMarkerAnnotationView
for reuse
Can I get an app that does not lag?
This can be a minimal reproducible instance:
MapView.swift
import SwiftUI
import MapKit
struct MapView: UIViewRepresentable {
let locationManager = CLLocationManager()
let mapView: MKMapView = MKMapView(body: .zero)
func makeCoordinator() -> MapViewCoordinator{
MapViewCoordinator(self)
}
func makeUIView(context: Context) -> MKMapView {
mapView.register(MKMarkerAnnotationView.self, forAnnotationViewWithReuseIdentifier: MapViewCoordinator.clusterReuseId)
mapView.register(CustomMKMarkerAnnotationView.self, forAnnotationViewWithReuseIdentifier: CustomMKMarkerAnnotationView.ReuseId)
mapView.delegate = context.coordinator
var annotations = [MKPointAnnotation]()
for _ in 0...5000 {
let annotation = MKPointAnnotation()
annotation.title = "Take a look at"
annotation.coordinate = CLLocationCoordinate2D(latitude: Double.random(in: 50...52), longitude: Double.random(in: 0...2))
annotations.append(annotation)
}
mapView.addAnnotations(annotations)
return mapView
}
func updateUIView(_ uiView: MKMapView, context: UIViewRepresentableContext<MapView>) {
}
}
MapViewCoordinator.swift
import Basis
import MapKit
class MapViewCoordinator: NSObject, MKMapViewDelegate {
var mapViewController: MapView
static let clusterReuseId = "cluster"
init(_ management: MapView) {
self.mapViewController = management
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
if (annotation is MKUserLocation) { return nil }
if let cluster = annotation as? MKClusterAnnotation {
let markerAnnotationView: MKMarkerAnnotationView
if let dequeued = mapView.dequeueReusableAnnotationView(withIdentifier: Self.clusterReuseId, for: cluster) as? MKMarkerAnnotationView {
markerAnnotationView = dequeued
markerAnnotationView.annotation = cluster
} else {
markerAnnotationView = MKMarkerAnnotationView(annotation: cluster, reuseIdentifier: Self.clusterReuseId)
}
markerAnnotationView.glyphText = String(cluster.memberAnnotations.rely)
markerAnnotationView.markerTintColor = UIColor.systemBlue
markerAnnotationView.canShowCallout = false
return markerAnnotationView
}
let annotationView: CustomMKMarkerAnnotationView
guard let annotation = annotation as? MKPointAnnotation else { return nil }
if let dequeuedView = mapView.dequeueReusableAnnotationView(
withIdentifier: CustomMKMarkerAnnotationView.ReuseId) as? CustomMKMarkerAnnotationView
{
annotationView = dequeuedView
annotationView.annotation = annotation
}
else
{
annotationView = CustomMKMarkerAnnotationView(annotation: annotation, reuseIdentifier: CustomMKMarkerAnnotationView.ReuseId)
}
annotationView.clusteringIdentifier = CustomMKMarkerAnnotationView.ReuseId
return annotationView
}
}
CustomMKMarkerAnnotationView.swift
import MapKit
let clusterId = "clusterId"
class CustomMKMarkerAnnotationView: MKMarkerAnnotationView {
static let ReuseId = "customAnnotation"
override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
tremendous.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
clusteringIdentifier = clusterId
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been carried out")
}
override func prepareForDisplay() {
tremendous.prepareForDisplay()
}
}