Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Poor performance on MKMapView clustering in iOS 11

Tags:

ios

swift

mapkit

I've been using third-party libraries for handling markers clustering. Since iOS 11 has its own implementation, I've decided to move on and remove third-party libraries on behalf "native" implementation.

I've downloaded the example app from WWDC 2017 and follow the same steps, so:

  • Connect MKMapView Outlet
  • Implement MKAnnotation protocol for my model
  • Create a MKMarkerAnnotationView for marker's view
  • Create a MKMarkerAnnotationView for cluster's view
  • Register both annotations on my mapView reference with register(_:forAnnotationViewWithReuseIdentifier:) function
  • Add annotations to my map

However, while using third-party libraries everything was fine, with this method I get a very poor performance when I pan on my mapView and change region. CPU usage raises up to 90% while memory seems to stay stable, and I feel delay in moving and sometimes even app crashes. I'm loading about 600 annotations.

Any suggestion?

Here is the code:

class MapViewClusteringViewController: UIViewController, MKMapViewDelegate {

  @IBOutlet weak var mapView: MKMapView!
  private var databaseService: LocalDataService!

  override func viewDidLoad() {
    super.viewDidLoad()
    mapView.delegate = self
    mapView.register(StopMarker.self, forAnnotationViewWithReuseIdentifier: MKMapViewDefaultAnnotationViewReuseIdentifier)
    mapView.register(StopCluster.self, forAnnotationViewWithReuseIdentifier: MKMapViewDefaultClusterAnnotationViewReuseIdentifier)

    databaseService.fetchMarkers { markers in
      mapView.addAnnotation(markers)
    }
  }
}

class StopMarker: MKMarkerAnnotationView {
  override var annotation: MKAnnotation? {
    willSet {
      clusteringIdentifier = "busStopCluster"
      subtitleVisibility = .adaptive
      markerTintColor = .red
    }
  }
}

class StopCluster: MKMarkerAnnotationView {
  override init(annotation: MKAnnotation?, reuseIdentifier: String?) {
    super.init(annotation: annotation, reuseIdentifier: reuseIdentifier)
    displayPriority = .defaultHigh
  }

  required init?(coder aDecoder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }

  override var annotation: MKAnnotation? {
    willSet {
      if let cluster = newValue as? MKClusterAnnotation {
        markerTintColor = .green
        glyphText = "\(cluster.memberAnnotations.count)"
      }
    }
  }
}

class StopAnnotation: NSObject, MKAnnotation {
  var coordinate: CLLocationCoordinate2D
  var title: String?

  init(coordinate: CLLocationCoordinate2D, title: String) {
    self.coordinate = coordinate
    self.title = title
  }
}
like image 775
Javier Cancio Avatar asked Mar 13 '18 21:03

Javier Cancio


1 Answers

From here, you can read:

Do not create instances of this class yourself. MapKit automatically creates cluster annotations when two or more annotation views become grouped too closely together on the map surface.

You may try without creating instance of this class by yourself.

like image 149
A STEFANI Avatar answered Oct 24 '22 09:10

A STEFANI