     }
   }
   
+  /// Annotation that should be animated in and out when appearing and
+  /// disappearing. Also, when updating this array, only the differnces will
+  /// be animated for any annotations conforming to `TKUIIdentifiableAnnotation`
+  public var animatedAnnotations = [MKAnnotation]() {
+    didSet {
+      guard let mapView = mapView else { return }
+      
+      let removed = oldValue.elements(notIn: animatedAnnotations)
+      let added = animatedAnnotations.elements(notIn: oldValue)
+      mapView.addAnnotations(added)
+
+      // The tricky thing here is this: We can only remove annotations that the
+      // map is aware of, i.e., if we have A:[1,2,3] => B:[2,3,4] => C:[3,4,5]
+      //
+      // When we get to C, we would remove B2, but that never got added to the
+      // map, instead the map contains A2. So mapView.remove(B2) will NOT remove
+      // A2.
+      if !removed.isEmpty {
+        let removedIDs = removed.identities
+        assert(removed.count == removedIDs.count)
+        let annotationsToRemove = mapView.annotations.filter {
+          guard let id = ($0 as? TKUIIdentifiableAnnotation)?.identity else { return false }
+          return removedIDs.contains(id)
+        }
+        mapView.removeAnnotations(annotationsToRemove)
+      }
+    }
+  }
+  
+  /// Annotations where each annotation can dynamically change, e.g., changing
+  /// its coordinate, title/subtitle, and preferred alpha
   public var dynamicAnnotations = [MKAnnotation]() {
     didSet {
       mapView?.removeAnnotations(oldValue)

#else
  import TripKit
#endif

open class TKUIMapManager: TGMapManager {
  

  
  override open func cleanUp(_ mapView: MKMapView, animated: Bool) {
    removeOverlay(overlayPolygon)
    
    mapView.removeOverlays(overlays)
    mapView.removeAnnotations(animatedAnnotations)
    mapView.removeAnnotations(dynamicAnnotations)
    
    super.cleanUp(mapView, animated: animated)
  }
