From 869760cb2a5be0ab6c655b4a4483482cfb7f8fab Mon Sep 17 00:00:00 2001 From: reuk Date: Tue, 5 Jul 2022 13:56:08 +0100 Subject: [PATCH] ObjC: Add scoped notification observer --- .../juce_core/native/juce_mac_ObjCHelpers.h | 53 ++++++++++++ .../native/juce_ios_Windowing.mm | 31 +++---- .../native/juce_mac_NSViewComponentPeer.mm | 85 ++++--------------- 3 files changed, 79 insertions(+), 90 deletions(-) diff --git a/modules/juce_core/native/juce_mac_ObjCHelpers.h b/modules/juce_core/native/juce_mac_ObjCHelpers.h index e6f12d2848..8995472d65 100644 --- a/modules/juce_core/native/juce_mac_ObjCHelpers.h +++ b/modules/juce_core/native/juce_mac_ObjCHelpers.h @@ -520,4 +520,57 @@ private: BlockType block; }; +//============================================================================== +class ScopedNotificationCenterObserver +{ +public: + ScopedNotificationCenterObserver() = default; + + ScopedNotificationCenterObserver (id observerIn, SEL selector, NSNotificationName nameIn, id objectIn) + : observer (observerIn), name (nameIn), object (objectIn) + { + [[NSNotificationCenter defaultCenter] addObserver: observer + selector: selector + name: name + object: object]; + } + + ~ScopedNotificationCenterObserver() + { + if (observer != nullptr && name != nullptr) + { + [[NSNotificationCenter defaultCenter] removeObserver: observer + name: name + object: object]; + } + } + + ScopedNotificationCenterObserver (ScopedNotificationCenterObserver&& other) noexcept + { + swap (other); + } + + ScopedNotificationCenterObserver& operator= (ScopedNotificationCenterObserver&& other) noexcept + { + auto moved = std::move (other); + swap (moved); + return *this; + } + + ScopedNotificationCenterObserver (const ScopedNotificationCenterObserver&) = delete; + ScopedNotificationCenterObserver& operator= (const ScopedNotificationCenterObserver&) = delete; + +private: + void swap (ScopedNotificationCenterObserver& other) noexcept + { + std::swap (other.observer, observer); + std::swap (other.name, name); + std::swap (other.object, object); + } + + id observer = nullptr; + NSNotificationName name = nullptr; + id object = nullptr; +}; + } // namespace juce diff --git a/modules/juce_gui_basics/native/juce_ios_Windowing.mm b/modules/juce_gui_basics/native/juce_ios_Windowing.mm index 434b39e6f9..e612adc77f 100644 --- a/modules/juce_gui_basics/native/juce_ios_Windowing.mm +++ b/modules/juce_gui_basics/native/juce_ios_Windowing.mm @@ -710,24 +710,14 @@ public: { static DelegateClass delegateClass; - delegate = [delegateClass.createInstance() init]; - object_setInstanceVariable (delegate, "owner", this); + delegate.reset ([delegateClass.createInstance() init]); + object_setInstanceVariable (delegate.get(), "owner", this); JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector") - [[NSNotificationCenter defaultCenter] addObserver: delegate - selector: @selector (darkModeChanged:) - name: UIViewComponentPeer::getDarkModeNotificationName() - object: nil]; + observer.emplace (delegate.get(), @selector (darkModeChanged:), UIViewComponentPeer::getDarkModeNotificationName(), nil); JUCE_END_IGNORE_WARNINGS_GCC_LIKE } - ~NativeDarkModeChangeDetectorImpl() - { - object_setInstanceVariable (delegate, "owner", nullptr); - [[NSNotificationCenter defaultCenter] removeObserver: delegate]; - [delegate release]; - } - void darkModeChanged() { Desktop::getInstance().darkModeChanged(); @@ -741,20 +731,19 @@ private: addIvar ("owner"); JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector") - addMethod (@selector (darkModeChanged:), darkModeChanged); + addMethod (@selector (darkModeChanged:), [] (id self, SEL, NSNotification*) + { + if (auto* owner = getIvar (self, "owner")) + owner->darkModeChanged(); + }); JUCE_END_IGNORE_WARNINGS_GCC_LIKE registerClass(); } - - static void darkModeChanged (id self, SEL, NSNotification*) - { - if (auto* owner = getIvar (self, "owner")) - owner->darkModeChanged(); - } }; - id delegate = nil; + NSUniquePtr delegate; + Optional observer; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeDarkModeChangeDetectorImpl) }; diff --git a/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm b/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm index fabfbde401..3099552150 100644 --- a/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm +++ b/modules/juce_gui_basics/native/juce_mac_NSViewComponentPeer.mm @@ -144,12 +144,7 @@ public: resetTrackingArea (view); - notificationCenter = [NSNotificationCenter defaultCenter]; - - [notificationCenter addObserver: view - selector: frameChangedSelector - name: NSViewFrameDidChangeNotification - object: view]; + scopedObservers.emplace_back (view, frameChangedSelector, NSViewFrameDidChangeNotification, view); [view setPostsFrameChangedNotifications: YES]; @@ -225,25 +220,10 @@ public: [window setTabbingMode: NSWindowTabbingModeDisallowed]; #endif - [notificationCenter addObserver: view - selector: frameChangedSelector - name: NSWindowDidMoveNotification - object: window]; - - [notificationCenter addObserver: view - selector: frameChangedSelector - name: NSWindowDidMiniaturizeNotification - object: window]; - - [notificationCenter addObserver: view - selector: @selector (windowWillMiniaturize:) - name: NSWindowWillMiniaturizeNotification - object: window]; - - [notificationCenter addObserver: view - selector: @selector (windowDidDeminiaturize:) - name: NSWindowDidDeminiaturizeNotification - object: window]; + scopedObservers.emplace_back (view, frameChangedSelector, NSWindowDidMoveNotification, window); + scopedObservers.emplace_back (view, frameChangedSelector, NSWindowDidMiniaturizeNotification, window); + scopedObservers.emplace_back (view, @selector (windowWillMiniaturize:), NSWindowWillMiniaturizeNotification, window); + scopedObservers.emplace_back (view, @selector (windowDidMiniaturize:), NSWindowDidMiniaturizeNotification, window); } auto alpha = component.getAlpha(); @@ -267,7 +247,8 @@ public: CVDisplayLinkStop (displayLink); dispatch_source_cancel (displaySource); - [notificationCenter removeObserver: view]; + scopedObservers.clear(); + setOwner (view, nullptr); if ([view superview] != nil) @@ -797,24 +778,7 @@ public: void redirectWillMoveToWindow (NSWindow* newWindow) { - if (auto* currentWindow = [view window]) - { - [notificationCenter removeObserver: view - name: NSWindowDidMoveNotification - object: currentWindow]; - - [notificationCenter removeObserver: view - name: NSWindowWillMiniaturizeNotification - object: currentWindow]; - - [notificationCenter removeObserver: view - name: NSWindowDidBecomeKeyNotification - object: currentWindow]; - - [notificationCenter removeObserver: view - name: NSWindowDidChangeScreenNotification - object: currentWindow]; - } + windowObservers.clear(); if (isSharedWindow && [view window] == window && newWindow == nullptr) { @@ -1256,30 +1220,11 @@ public: if (auto* currentWindow = [view window]) { - [notificationCenter addObserver: view - selector: dismissModalsSelector - name: NSWindowWillMoveNotification - object: currentWindow]; - - [notificationCenter addObserver: view - selector: dismissModalsSelector - name: NSWindowWillMiniaturizeNotification - object: currentWindow]; - - [notificationCenter addObserver: view - selector: becomeKeySelector - name: NSWindowDidBecomeKeyNotification - object: currentWindow]; - - [notificationCenter addObserver: view - selector: resignKeySelector - name: NSWindowDidResignKeyNotification - object: currentWindow]; - - [notificationCenter addObserver: view - selector: @selector (windowDidChangeScreen:) - name: NSWindowDidChangeScreenNotification - object: currentWindow]; + windowObservers.emplace_back (view, dismissModalsSelector, NSWindowWillMoveNotification, currentWindow); + windowObservers.emplace_back (view, dismissModalsSelector, NSWindowWillMiniaturizeNotification, currentWindow); + windowObservers.emplace_back (view, becomeKeySelector, NSWindowDidBecomeKeyNotification, currentWindow); + windowObservers.emplace_back (view, resignKeySelector, NSWindowDidResignKeyNotification, currentWindow); + windowObservers.emplace_back (view, @selector (windowDidChangeScreen:), NSWindowDidChangeScreenNotification, currentWindow); updateCVDisplayLinkScreen(); } @@ -1659,7 +1604,6 @@ public: bool windowRepresentsFile = false; bool isAlwaysOnTop = false, wasAlwaysOnTop = false; String stringBeingComposed; - NSNotificationCenter* notificationCenter = nil; Rectangle lastSizeBeforeZoom; RectangleList deferredRepaints; @@ -1892,6 +1836,9 @@ private: int numFramesToSkipMetalRenderer = 0; std::unique_ptr> metalRenderer; + std::vector scopedObservers; + std::vector windowObservers; + JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NSViewComponentPeer) };