From 1e7b91b4d20516c00039f04f4ddf8bcd87e834bc Mon Sep 17 00:00:00 2001 From: reuk Date: Tue, 2 Jan 2024 19:06:23 +0000 Subject: [PATCH] FileChooser: Avoid potential issue when viewDidDismiss and file selection callbacks are interleaved viewDidDisappear may be called when a file is successfully selected. presentationControllerDidDismiss is only called when the controller is dismissed manually by the user, e.g. by tapping outside the sheet, or by dragging it away. Checking for sheet dismissal is necessary in iOS 15, but not in iOS 17. In iOS 17, tapping outside the file chooser causes a callback to documentPickerWasCancelled instead. --- .../filebrowser/juce_FileChooser.cpp | 11 ++++--- .../native/juce_FileChooser_ios.mm | 30 +++++++------------ 2 files changed, 16 insertions(+), 25 deletions(-) diff --git a/modules/juce_gui_basics/filebrowser/juce_FileChooser.cpp b/modules/juce_gui_basics/filebrowser/juce_FileChooser.cpp index c017707716..40d980e177 100644 --- a/modules/juce_gui_basics/filebrowser/juce_FileChooser.cpp +++ b/modules/juce_gui_basics/filebrowser/juce_FileChooser.cpp @@ -259,15 +259,14 @@ URL FileChooser::getURLResult() const void FileChooser::finished (const Array& asyncResults) { - std::function callback; - std::swap (callback, asyncCallback); + const auto callback = std::exchange (asyncCallback, nullptr); - results = asyncResults; + results = asyncResults; - pimpl.reset(); + pimpl.reset(); - if (callback) - callback (*this); + if (callback) + callback (*this); } #if ! JUCE_ANDROID diff --git a/modules/juce_gui_basics/native/juce_FileChooser_ios.mm b/modules/juce_gui_basics/native/juce_FileChooser_ios.mm index e14579d1ff..ff1efa1be5 100644 --- a/modules/juce_gui_basics/native/juce_FileChooser_ios.mm +++ b/modules/juce_gui_basics/native/juce_FileChooser_ios.mm @@ -27,7 +27,7 @@ - (void) setParent: (FileChooser::Native*) ptr; @end -@interface FileChooserDelegateClass : NSObject +@interface FileChooserDelegateClass : NSObject - (id) initWithOwner: (FileChooser::Native*) owner; @end @@ -42,7 +42,6 @@ namespace juce //============================================================================== class FileChooser::Native final : public FileChooser::Pimpl, public detail::NativeModalWrapperComponent, - public AsyncUpdater, public std::enable_shared_from_this { public: @@ -86,16 +85,9 @@ public: #endif } - void handleAsyncUpdate() override - { - pickerWasCancelled(); - } - //============================================================================== void didPickDocumentsAtURLs (NSArray* urls) { - cancelPendingUpdate(); - const auto isWriting = controller.get().documentPickerMode == UIDocumentPickerModeExportToService || controller.get().documentPickerMode == UIDocumentPickerModeMoveToService; const auto accessOptions = isWriting ? 0 : NSFileCoordinatorReadingWithoutChanges; @@ -223,12 +215,14 @@ private: [controller.get() setDelegate: delegate.get()]; + if (auto* pc = [controller.get() presentationController]) + [pc setDelegate: delegate.get()]; + displayNativeWindowModally (fileChooser.parent); } void passResultsToInitiator (Array urls) { - cancelPendingUpdate(); exitModalState (0); // If the caller attempts to show a platform-native dialog box inside the results callback (e.g. in the DialogsDemo) @@ -310,7 +304,7 @@ private: //============================================================================== FileChooser& owner; - NSUniquePtr> delegate; + NSUniquePtr> delegate; NSUniquePtr controller; //============================================================================== @@ -351,14 +345,6 @@ std::shared_ptr FileChooser::showPlatformDialog (FileChooser ptr = parent->weak_from_this(); } -- (void) viewDidDisappear: (BOOL) animated -{ - [super viewDidDisappear: animated]; - - if (auto nativeParent = ptr.lock()) - nativeParent->triggerAsyncUpdate(); -} - @end @implementation FileChooserDelegateClass @@ -393,4 +379,10 @@ JUCE_END_IGNORE_WARNINGS_GCC_LIKE owner->pickerWasCancelled(); } +- (void) presentationControllerDidDismiss: (UIPresentationController *) presentationController +{ + if (owner != nullptr) + owner->pickerWasCancelled(); +} + @end