Annotationen updaten während User über die map schwenkt

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Annotationen updaten während User über die map schwenkt

    Hi,
    Ich habe eine Menge Annotationen und versuche diese auf einer Map zu laden.

    Leider lagt die Map durchgehend und obwohl ich Cluster einsetze spinnt alles, wenn der User näher an die Map heranzoomt.
    Meiner Meinung nach liegt das Problem daran, dass die Map gleichzeitig mehrere Annotationen lädt.
    Also habe ich mir überlegt, immer nur die Annotationen zu laden, welche sich auf dem Bildschirm befinden.

    Ich habe bereits herausgefunden, wie man checkt ob sich ein Annotation auf dem Bildschirm befindet und nur diese zu laden. Sobald der User jedoch die Map herumschwenkt, updatet die Map nicht und es werden keine neuen Annotationen angezeigt.

    Habt ihr Lösungsansätze?

    Vielen Dank schonmal im Voraus.
  • verstehe ich krieg jedoch immer wieder fehler wenn es zB darum geht regionDidChange in meine mapView Funktion einzubauen
    wenn ich zum Beispiel das mache:

    Quellcode

    1. func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation, regionDidChangeAnimated animated: Bool) -> MKAnnotationView? {
    2. ...

    wird die Funktion gar nicht erst exekutiert, auch nicht wenn sich die Region ändert
  • Hast Du auch den delegate vom MKMapView gesetzt? ;)

    Hm, woher hast Du diese Funktion? ?(

    Quellcode

    1. func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation, regionDidChangeAnimated animated: Bool) -> MKAnnotationView?
    Du kannst natürlich nur Delegate Funktionen verwenden, die auch im MKMapViewDelegate Protocol definiert sind.

    Dort gibt es mapView(_:regionDidChangeAnimated:) und mapView(_:viewFor:) aber nicht mapView(_:viewFor:regionDidChangeAnimated:). ^^

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von MCDan ()

  • Wenn man mit iOS oder anderen Klassen arbeitet, dann ist es sinnvoll mal einen Blick in die Doku zur Klasse zu werfen. ;)

    Ok, bei manchen Klassen gibt es gefühlt hunderte Funktionen/Methoden, aber allgemein sind diese nach Themen gruppiert, was den Überblick über die Funktionen/Methode erleichtert.

    Unter dem Gruppennamen Annotating the Map findet man dann z.B. das Property annotations, über welches man an die aktuellen annotations auf der Map kommt. ;)

    Wenn Du schon die Methode addAnnotation(_:) kennst, dann gibt es am Ende der Doku zu dieser Funktion/Methode unter See Also eine Liste mit weiteren, zum Thema passenden Funktionen/Methoden. Darüber lässt sich dann z.B. auch die Info zum Property annotations finden.
  • ok update:
    hab das ganze basierend auf deinen links auf folgendes geändert:

    Quellcode

    1. func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
    2. let visRect = mapView.visibleMapRect
    3. let allAnnotations = mapView.annotations
    4. let inRectAnnotations = mapView.annotations(in: visRect)
    5. mapView.removeAnnotations(allAnnotations)
    6. mapView.addAnnotations(inRectAnnotations as AnyHashable as! [MKAnnotation])
    7. }
    leider gibt's einen "Signal Sigabrt" fehler
  • Hm, damit entfernst Du zwar die Annotations, die nicht mehr sichtbar sind, allerdings werden damit auch keine neuen hinzugefügt, die evtl. durch die Änderung der Region sichtbar würden.

    Wenn der MapView auch die User Location anzeigt, dann gibt es dafür natürlich auch eine Annotation. Ich weiß jetzt nicht ob man diese User Location Annotation über removeAnnotations(_:) entfernen darf. Diese musst Du also ggf. vorher aus allAnnotations entfernen.

    Anbei ein Objektive-C Code wie das Update der Region z.B. bei einer App von mir aussieht:

    C-Quellcode

    1. - (void)updateAnnotationsForRegion:(MKCoordinateRegion)region
    2. {
    3. NSMutableArray *newAnnotations = [self anotationsInRegion:region expansion:1.5]; // Ermittelt alle Annotations in der übergebenen Region
    4. if (self.mapView.annotations.count > 0)
    5. {
    6. NSMutableArray *annotationsToRemove = [self.mapView.annotations mutableCopy];
    7. [annotationsToRemove removeObjectsInArray:newAnnotations];
    8. [annotationsToRemove removeObject:self.mapView.userLocation];
    9. if (annotationsToRemove.count > 0)
    10. [self.mapView removeAnnotations:annotationsToRemove];
    11. }
    12. [newAnnotations removeObjectsInArray:self.mapView.annotations];
    13. [self.mapView addAnnotations:newAnnotations];
    14. }
    Alles anzeigen
  • Nochmal die Doku _genau_ lesen! annotations(in:) gibt ein Set<AnyHashable> zurück und addAnnotations() verlangt als Parameter ein Array<MKAnnotation>. Typcasting mit as! [MKAnnotation] geht also nicht, ergo SigAbrt.
    Keine Ahnung, warum Apple die API so designt hat.
    Möglicherweise hilft inRectAnnotations.compactMap{ $0 as? MKAnnotation }.
    Das iPhone sagt: "Zum Antworten streichen". Wie? Echt Jetzt? Muß ich erst die Wohnung streichen!?
  • genial! so langsam wird's

    deine Idee mit dem ".compactMap" hat funktioniert torquato, vielen Dank!

    dazu hab ich einige Ideen aus deinem objective c-Code genommen, McDan, und in Swift 4 umgeschrieben, was auch super funktioniert

    Jetzt passiert nur folgendes:
    Wenn ich die Region ändere, werden alle Annotationen gelöscht, die sich außerhalb des "Displays" befinden. Alle anderen bleiben [also genau wie geplant]
    Wenn ich nun aber wieder herauszoome, tauchen die alten annotations nicht wieder auf.

    mapView.removeAnnotations(allAnnotations) löscht die Annotationen also komplett aus dem Code und nicht nur temporär, sodass sie später wieder hinzugefügt werden können

    wisst ihr dafür auch eine lösung?
  • ok ich habs

    hab eine art backup ordner erstellt dem jede Annotation hinzugefügt wird die irgendwann erstellt wird

    falls "regionWillChange" eintritt werden alle Annotationen aus diesem backup ordner geladen. Sobald sich die Region geändert hat werden alle bis auf die im visibleMpaRect wieder gelöscht

    die Annotationen flackern zwar manchmal, wenn sie neu geladen werden aber das ist kein allzu großes Problem

    sehr geil
    Tausend Dank euch!!

    PS: falls euch eine bessere Idee einfällt, bei denen die Annotationen nicht flackern bin ich immer offen für verbesserungsvorschläge
  • Quellcode

    1. func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool {
    2. print("Region did Change")
    3. updateAnnotations(for: mapView.region)
    4. }
    5. func updateAnnotations(for Region: MKCoordinateRegion) {
    6. let visRect = mapView.visibleMapRect
    7. let newAnnotations = mapView.annotations(in: visRect).compactMap { $0 as ? MKAnnotation }
    8. let allAnnotations = mapView.annotations
    9. mapView.removeAnnotations(allAnnotations)
    10. print("annotations removed")
    11. mapView.addAnnotations(newAnnotations)
    12. print("annotations added")
    13. }
    14. func mapView(_ mapView: MKMapView, regionWillChangeAnimated animated: Bool) {
    15. mapView.addAnnotations(backUpAnnotations)
    16. print("Region will change \n backUpAnnotations added)
    17. }
    Alles anzeigen
  • Über updateAnnotations() entfernst Du ja nur die Annotations, die sich nicht mehr im visibleMapRect befinden.

    Du musst also in dem removeAnnotations Array die Annotations entfernen, die weiterhin angezeigt werden. Also alle, die sich im keepAnnotations Array befinden.

    C-Quellcode

    1. func updateAnnotations(for Region: MKCoordinateRegion) {
    2. let visRect = mapView.visibleMapRect
    3. let keepAnnotations = mapView.annotations(in: visRect).compactMap { $0 as ? MKAnnotation }
    4. let removeAnnotations = mapView.annotations
    5. // Alle Annotations entfernen, die weiterhin angezeigt werden sollen
    6. removeAnnotations.removeAll(where: { keepAnnotations.contains($0) })
    7. mapView.removeAnnotations(removeAnnotations)
    8. print("annotations removed")
    9. }
    Alles anzeigen
  • Dann kann man sich auch die Heap-Allocation eines neuen Arrays, die bei compactMap entsteht, sparen. Typecasting braucht man dann (wahrscheinlich) trotzdem noch. Also so ungefähr:

    Quellcode

    1. func updateAnnotations(for Region: MKCoordinateRegion) {
    2. let visRect = mapView.visibleMapRect
    3. let keepAnnotations = mapView.annotations(in: visRect)
    4. var removeAnnotations = mapView.annotations
    5. // Alle Annotations entfernen, die weiterhin angezeigt werden sollen
    6. removeAnnotations.removeAll(where: {
    7. if let annotation = $0 as? AnyHashable {
    8. return keepAnnotations.contains(annotation)
    9. }
    10. return false
    11. })
    12. mapView.removeAnnotations(removeAnnotations)
    13. print("annotations removed")
    14. }
    Alles anzeigen

    Das nur noch mal so als weiteren Gedanken reingeworfen…
    Das iPhone sagt: "Zum Antworten streichen". Wie? Echt Jetzt? Muß ich erst die Wohnung streichen!?