     mapView?.removeOverlay(polygon)
   }
   
+}
+
+// MARK: - Updating animated annotations
+
+fileprivate extension Array where Element: MKAnnotation {
+  fileprivate var identities: [String] {
+    return compactMap { ($0 as? TKUIIdentifiableAnnotation)?.identity }
+  }
+  
+  fileprivate func elements(notIn other: [Element]) -> [Element] {
+    let otherIDs = other.identities
+    return filter {
+      guard let id = ($0 as? TKUIIdentifiableAnnotation)?.identity else { return true }
+      return !otherIDs.contains(id)
+    }
+  }
 }
 
 // MARK: - Updating dynamic annotations

  
  override open func cleanUp(_ mapView: MKMapView, animated: Bool) {
    removeOverlay(overlayPolygon)
    overlays = []
    dynamicAnnotations = []
    
    super.cleanUp(mapView, animated: animated)
  }

    }
  }
  
  /// 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)
