iOS: FileChooser::browseForFileToOpen() leaks memory(in Instruments)

I’m new to iOS developing. If I’m saying really stupid thing, please tell me.

Every time I call FileChooser::browseForFileToOpen() and choose a file, it always says that it leaked memory.
But JUCE’s leak detector wasn’t triggered.
Was this due to the iOS API? If so, how can I fix?

I tested on new GUI Application project, adding a button with simple onClick callback.
This is my onClick implementation.

juce::FileChooser chooser("Select a file...", juce::File::getSpecialLocation(juce::File::userDocumentsDirectory));
if (chooser.browseForFileToOpen())
{
    auto result = chooser.getResult();
    //do nothing, but leaks memory.
}
Stack Trace from Instruments

0 libsystem_malloc.dylib malloc_zone_calloc
1 libsystem_malloc.dylib calloc
2 libobjc.A.dylib class_createInstance
3 libobjc.A.dylib +[NSObject allocWithZone:]
4 FileChooserLeakTest juce::FileChooser::Native::didPickDocumentAtURL(NSURL*) /Applications/tracktion_engine/modules/juce/modules/juce_gui_basics/native/juce_ios_FileChooser.mm:222
5 FileChooserLeakTest juce::FileChooser::Native::FileChooserDelegateClass::didPickDocumentAtURL(objc_object*, objc_selector*, UIDocumentPickerViewController*, NSURL*) /Applications/tracktion_engine/modules/juce/modules/juce_gui_basics/native/juce_ios_FileChooser.mm:301
6 UIKitCore __74-[UIDocumentPickerViewController _callDelegateWithSelectedURLsAndDismiss:]_block_invoke
7 UIKitCore -[UIPresentationController transitionDidFinish:]
8 UIKitCore -[_UICurrentContextPresentationController transitionDidFinish:]
9 UIKitCore __56-[UIPresentationController runTransitionForCurrentState]_block_invoke.425
10 UIKitCore -[_UIViewControllerTransitionContext completeTransition:]
11 UIKitCore -[UITransitionView notifyDidCompleteTransition:]
12 UIKitCore -[UITransitionView _didCompleteTransition:]
13 UIKitCore -[UITransitionView _transitionDidStop:finished:]
14 UIKitCore -[UIViewAnimationState sendDelegateAnimationDidStop:finished:]
15 UIKitCore -[UIViewAnimationState animationDidStop:finished:]
16 UIKitCore -[UIViewAnimationState animationDidStop:finished:]
17 QuartzCore CA::Layer::run_animation_callbacks(void*)
18 libdispatch.dylib _dispatch_client_callout
19 libdispatch.dylib _dispatch_main_queue_callback_4CF
20 CoreFoundation CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE
21 CoreFoundation __CFRunLoopRun
22 CoreFoundation CFRunLoopRunSpecific
23 Foundation -[NSRunLoop(NSRunLoop) runMode:beforeDate:]
24 FileChooserLeakTest juce::MessageManager::runDispatchLoopUntil(int) /Applications/tracktion_engine/modules/juce/modules/juce_events/native/juce_ios_MessageManager.mm:62
25 FileChooserLeakTest juce::ModalComponentManager::runEventLoopForCurrentComponent() /Applications/tracktion_engine/modules/juce/modules/juce_gui_basics/components/juce_ModalComponentManager.cpp:276
26 FileChooserLeakTest juce::Component::runModalLoop() /Applications/tracktion_engine/modules/juce/modules/juce_gui_basics/components/juce_Component.cpp:1652
27 FileChooserLeakTest juce::FileChooser::Native::runModally() /Applications/tracktion_engine/modules/juce/modules/juce_gui_basics/native/juce_ios_FileChooser.mm:131
28 FileChooserLeakTest juce::FileChooser::showDialog(int, juce::FilePreviewComponent*) /Applications/tracktion_engine/modules/juce/modules/juce_gui_basics/filebrowser/juce_FileChooser.cpp:163
29 FileChooserLeakTest juce::FileChooser::browseForFileToOpen(juce::FilePreviewComponent*) /Applications/tracktion_engine/modules/juce/modules/juce_gui_basics/filebrowser/juce_FileChooser.cpp:121
30 FileChooserLeakTest MainComponent::MainComponent()::_0::operator()() const /Users/DicklessGreat/Desktop/FileChooserLeakTest/Source/MainComponent.cpp:13 31 FileChooserLeakTest decltype(std::__1::forward<MainComponent::MainComponent()::_0&>(fp)()) std::__1::__invokeMainComponent::MainComponent()::$_0&(MainComponent::MainComponent()::_0&&&) /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/type_traits:4361 32 FileChooserLeakTest void std::__1::__invoke_void_return_wrapper<void>::__call<MainComponent::MainComponent()::_0&>(MainComponent::MainComponent()::_0&&&) /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../include/c++/v1/__functional_base:349 33 FileChooserLeakTest std::__1::__function::__alloc_func<MainComponent::MainComponent()::_0, std::__1::allocatorMainComponent::MainComponent()::$_0, void ()>::operator()() /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/…/include/c++/v1/functional:1527
34 FileChooserLeakTest std::__1::__function::__func<MainComponent::MainComponent()::_0, std::__1::allocator<MainComponent::MainComponent()::_0>, void ()>::operator()() /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/…/include/c++/v1/functional:1651
35 FileChooserLeakTest std::__1::__function::__value_func<void ()>::operator()() const /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/…/include/c++/v1/functional:1799
36 FileChooserLeakTest std::__1::function<void ()>::operator()() const /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/…/include/c++/v1/functional:2347
37 FileChooserLeakTest juce::Button::sendClickMessage(juce::ModifierKeys const&) /Applications/tracktion_engine/modules/juce/modules/juce_gui_basics/buttons/juce_Button.cpp:408
38 FileChooserLeakTest juce::Button::internalClickCallback(juce::ModifierKeys const&) /Applications/tracktion_engine/modules/juce/modules/juce_gui_basics/buttons/juce_Button.cpp:351
39 FileChooserLeakTest juce::Button::mouseUp(juce::MouseEvent const&) /Applications/tracktion_engine/modules/juce/modules/juce_gui_basics/buttons/juce_Button.cpp:471
40 FileChooserLeakTest juce::Component::internalMouseUp(juce::MouseInputSource, juce::Point, juce::Time, juce::ModifierKeys, float, float, float, float, float) /Applications/tracktion_engine/modules/juce/modules/juce_gui_basics/components/juce_Component.cpp:2435
41 FileChooserLeakTest juce::MouseInputSourceInternal::sendMouseUp(juce::Component&, juce::Point, juce::Time, juce::ModifierKeys) /Applications/tracktion_engine/modules/juce/modules/juce_gui_basics/mouse/juce_MouseInputSource.cpp:155
42 FileChooserLeakTest juce::MouseInputSourceInternal::setButtons(juce::Point, juce::Time, juce::ModifierKeys) /Applications/tracktion_engine/modules/juce/modules/juce_gui_basics/mouse/juce_MouseInputSource.cpp:197
43 FileChooserLeakTest juce::MouseInputSourceInternal::handleEvent(juce::ComponentPeer&, juce::Point, juce::Time, juce::ModifierKeys, float, float, juce::PenDetails) /Applications/tracktion_engine/modules/juce/modules/juce_gui_basics/mouse/juce_MouseInputSource.cpp:334
44 FileChooserLeakTest juce::MouseInputSource::handleEvent(juce::ComponentPeer&, juce::Point, long long, juce::ModifierKeys, float, float, juce::PenDetails const&) /Applications/tracktion_engine/modules/juce/modules/juce_gui_basics/mouse/juce_MouseInputSource.cpp:634
45 FileChooserLeakTest juce::ComponentPeer::handleMouseEvent(juce::MouseInputSource::InputSourceType, juce::Point, juce::ModifierKeys, float, float, long long, juce::PenDetails, int) /Applications/tracktion_engine/modules/juce/modules/juce_gui_basics/windows/juce_ComponentPeer.cpp:88
46 FileChooserLeakTest juce::UIViewComponentPeer::handleTouches(UIEvent*, bool, bool, bool) /Applications/tracktion_engine/modules/juce/modules/juce_gui_basics/native/juce_ios_UIViewComponentPeer.mm:896
47 FileChooserLeakTest -[JuceUIView touchesEnded:withEvent:] /Applications/tracktion_engine/modules/juce/modules/juce_gui_basics/native/juce_ios_UIViewComponentPeer.mm:492
48 UIKitCore -[UIWindow _sendTouchesForEvent:]
49 UIKitCore -[UIWindow sendEvent:]
50 UIKitCore -[UIApplication sendEvent:]
51 UIKitCore __dispatchPreprocessedEventFromEventQueue
52 UIKitCore __handleEventQueueInternal
53 CoreFoundation CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION
54 CoreFoundation __CFRunLoopDoSources0
55 CoreFoundation __CFRunLoopRun
56 CoreFoundation CFRunLoopRunSpecific
57 GraphicsServices GSEventRunModal
58 UIKitCore UIApplicationMain
59 FileChooserLeakTest juce::juce_iOSMain(int, char const**, void*) /Applications/tracktion_engine/modules/juce/modules/juce_gui_basics/native/juce_ios_Windowing.mm:428
60 FileChooserLeakTest juce::JUCEApplicationBase::main(int, char const**) /Applications/tracktion_engine/modules/juce/modules/juce_events/messages/juce_ApplicationBase.cpp:237
61 FileChooserLeakTest main /Users/DicklessGreat/Desktop/FileChooserLeakTest/Source/Main.cpp:105
62 libdyld.dylib start

Now I’ve changed the code, but it leaks yet.

//class member attribute
std::unique_ptr<FileChooser> fc;

//=========================onClick====================
fc = std::make_unique<FileChooser> ("Choose a file to open..."
                        , juce::File::getSpecialLocation(juce::File::userDocumentsDirectory)
                        , "*"
                        , true);
fc->launchAsync (FileBrowserComponent::openMode
                                 | FileBrowserComponent::canSelectFiles,
                                 [this] (const FileChooser& chooser)
                                 {
                                     auto result = chooser.getResult();
                                     createEditCtr(result);
                                 });

Strange thing is, I notice that it leaks sometimes after I choose a file and close the chooser.
Not always.
This is my almost first time to use Instruments, so wondering if I shouldn’t trust it and shouldn’t be much careful.(Of course, I think memory leaking is very big issue if it really did!)

Thanks for reporting!

1 Like

Thank you!
I’ve tested to open files and they stop leaking memory.
Yes, it works fine now!

I’m not familiar with objective-C, so I’m really appreciate your work.
And also, thank you for your opportunity to learn something new.
Keep good work!

Ah, Can I ask a question?
Why JUCE’s leak detector hadn’t been triggered before fix?
iOS’s FileChooser::Native class has JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR, but it didn’t detect leaks.(But Instruments said it leaked)
So I assumed that it was not due to JUCE, but it turned out to be…Why?

JUCE’s leak detector detects JUCE classes that have leaked and have the JUCE_DECLARE_LEAK_DETECTOR macro. In this case we were leaking an NSFileCoordinator object which is an Apple class and out of our control.

I got it.
I’ll keep it in mind when I make custom .mm file with objective-c objects.
Thanks!