diff --git a/shell/platform/darwin/ios/platform_view_ios.h b/shell/platform/darwin/ios/platform_view_ios.h index b93379d89a83d..5e1e581a3a92b 100644 --- a/shell/platform/darwin/ios/platform_view_ios.h +++ b/shell/platform/darwin/ios/platform_view_ios.h @@ -48,6 +48,20 @@ class PlatformViewIOS final : public PlatformView { void SetSemanticsEnabled(bool enabled) override; private: + /// Smart pointer for use with objective-c observers. + /// This guarentees we remove the observer. + class ScopedObserver { + public: + ScopedObserver(); + ~ScopedObserver(); + void reset(id observer); + ScopedObserver(const ScopedObserver&) = delete; + ScopedObserver& operator=(const ScopedObserver&) = delete; + + private: + id observer_; + }; + fml::WeakPtr owner_controller_; // Since the `ios_surface_` is created on the platform thread but // used on the GPU thread we need to protect it with a mutex. @@ -58,7 +72,7 @@ class PlatformViewIOS final : public PlatformView { std::unique_ptr accessibility_bridge_; fml::scoped_nsprotocol text_input_plugin_; fml::closure firstFrameCallback_; - fml::scoped_nsprotocol dealloc_view_controller_observer_; + ScopedObserver dealloc_view_controller_observer_; // |PlatformView| void HandlePlatformMessage(fml::RefPtr message) override; diff --git a/shell/platform/darwin/ios/platform_view_ios.mm b/shell/platform/darwin/ios/platform_view_ios.mm index af8bbfec1c570..bb37fa9610b2b 100644 --- a/shell/platform/darwin/ios/platform_view_ios.mm +++ b/shell/platform/darwin/ios/platform_view_ios.mm @@ -54,15 +54,15 @@ // Add an observer that will clear out the owner_controller_ ivar and // the accessibility_bridge_ in case the view controller is deleted. - dealloc_view_controller_observer_.reset([[NSNotificationCenter defaultCenter] - addObserverForName:FlutterViewControllerWillDealloc - object:owner_controller_.get() - queue:[NSOperationQueue mainQueue] - usingBlock:^(NSNotification* note) { - // Implicit copy of 'this' is fine. - accessibility_bridge_.reset(); - owner_controller_.reset(); - }]); + dealloc_view_controller_observer_.reset( + [[[NSNotificationCenter defaultCenter] addObserverForName:FlutterViewControllerWillDealloc + object:owner_controller_.get() + queue:[NSOperationQueue mainQueue] + usingBlock:^(NSNotification* note) { + // Implicit copy of 'this' is fine. + accessibility_bridge_.reset(); + owner_controller_.reset(); + }] retain]); if (owner_controller_) { ios_surface_ = @@ -174,4 +174,23 @@ new AccessibilityBridge(static_cast(owner_controller_.get().view), text_input_plugin_ = plugin; } +PlatformViewIOS::ScopedObserver::ScopedObserver() : observer_(nil) {} + +PlatformViewIOS::ScopedObserver::~ScopedObserver() { + if (observer_) { + [[NSNotificationCenter defaultCenter] removeObserver:observer_]; + [observer_ release]; + } +} + +void PlatformViewIOS::ScopedObserver::reset(id observer) { + if (observer != observer_) { + if (observer_) { + [[NSNotificationCenter defaultCenter] removeObserver:observer_]; + [observer_ release]; + } + observer_ = observer; + } +} + } // namespace flutter