diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm index d3c42ed446b071b755e17e4737ac38757679fbfa..f2f0550b8cece7496b7391eed26767d3de1696de 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews.mm @@ -100,12 +100,8 @@ void FlutterPlatformViewsController::OnDispose(FlutterMethodCall* call, FlutterR details:[NSString stringWithFormat:@"view id: '%lld'", viewId]]); return; } - - UIView* touch_interceptor = touch_interceptors_[viewId].get(); - [touch_interceptor removeFromSuperview]; - views_.erase(viewId); - touch_interceptors_.erase(viewId); - overlays_.erase(viewId); + // We wait for next submitFrame to dispose views. + views_to_dispose_.insert(viewId); result(nil); } @@ -213,6 +209,8 @@ void FlutterPlatformViewsController::Reset() { bool FlutterPlatformViewsController::SubmitFrame(bool gl_rendering, GrContext* gr_context, std::shared_ptr gl_context) { + DisposeViews(); + bool did_submit = true; for (size_t i = 0; i < composition_order_.size(); i++) { int64_t view_id = composition_order_[i]; @@ -265,12 +263,30 @@ void FlutterPlatformViewsController::DetachUnusedLayers() { for (int64_t view_id : active_composition_order_) { if (composition_order_set.find(view_id) == composition_order_set.end()) { + if (touch_interceptors_.find(view_id) == touch_interceptors_.end()) { + continue; + } [touch_interceptors_[view_id].get() removeFromSuperview]; [overlays_[view_id]->overlay_view.get() removeFromSuperview]; } } } +void FlutterPlatformViewsController::DisposeViews() { + if (views_to_dispose_.empty()) { + return; + } + + for (int64_t viewId : views_to_dispose_) { + UIView* touch_interceptor = touch_interceptors_[viewId].get(); + [touch_interceptor removeFromSuperview]; + views_.erase(viewId); + touch_interceptors_.erase(viewId); + overlays_.erase(viewId); + } + views_to_dispose_.clear(); +} + void FlutterPlatformViewsController::EnsureOverlayInitialized(int64_t overlay_id) { if (overlays_.count(overlay_id) != 0) { return; diff --git a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h index a0ebbac98b302c4ba1a71f9e07e79421b84fb691..0f2cfe3d57bad58926df2ca827ec6c93fe61060f 100644 --- a/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h +++ b/shell/platform/darwin/ios/framework/Source/FlutterPlatformViews_Internal.h @@ -91,6 +91,10 @@ class FlutterPlatformViewsController { GrContext* overlays_gr_context_; SkISize frame_size_; + // Method channel `OnDispose` calls adds the views to be disposed to this set to be disposed on + // the next frame. + std::unordered_set views_to_dispose_; + // A vector of embedded view IDs according to their composition order. // The last ID in this vector belond to the that is composited on top of all others. std::vector composition_order_; @@ -106,6 +110,8 @@ class FlutterPlatformViewsController { void OnRejectGesture(FlutterMethodCall* call, FlutterResult& result); void DetachUnusedLayers(); + // Dispose the views in `views_to_dispose_`. + void DisposeViews(); void EnsureOverlayInitialized(int64_t overlay_id); void EnsureGLOverlayInitialized(int64_t overlay_id, std::shared_ptr gl_context,