maui icon indicating copy to clipboard operation
maui copied to clipboard

[ios] fix memory leak in SearchBar

Open jonathanpeppers opened this issue 2 years ago • 5 comments

Context: https://github.com/dotnet/maui/pull/16346

This addresses the memory leak discovered by:

src/Core/src/Platform/iOS/MauiSearchBar.cs(36,63): error MA0001: Event 'TextSetOrChanged' could cause memory leaks in an NSObject subclass. Remove the event or add the [UnconditionalSuppressMessage("Memory", "MA0001")] attribute with a justification as to why the event will not leak.
src/Core/src/Platform/iOS/MauiSearchBar.cs(54,32): error MA0001: Event 'OnMovedToWindow' could cause memory leaks in an NSObject subclass. Remove the event or add the [UnconditionalSuppressMessage("Memory", "MA0001")] attribute with a justification as to why the event will not leak.
src/Core/src/Platform/iOS/MauiSearchBar.cs(55,32): error MA0001: Event 'EditingChanged' could cause memory leaks in an NSObject subclass. Remove the event or add the [UnconditionalSuppressMessage("Memory", "MA0001")] attribute with a justification as to why the event will not leak.
src/Core/src/Platform/iOS/MauiSearchBar.cs(70,31): error MA0003: Subscribing to events with instance method 'OnEditingChanged' could cause memory leaks in an NSObject subclass. Remove the subscription or convert the method to a static method.

I could reproduce a leak in a test such as:

await InvokeOnMainThreadAsync(() =>
{
    var layout = new Grid();
    var searchBar = new SearchBar();
    layout.Add(searchBar);
    var handler = CreateHandler<LayoutHandler>(layout);
    viewReference = new WeakReference(searchBar);
    handlerReference = new WeakReference(searchBar.Handler);
    platformViewReference = new WeakReference(searchBar.Handler.PlatformView);
});

await AssertionExtensions.WaitForGC(viewReference, handlerReference, platformViewReference);
Assert.False(viewReference.IsAlive, "SearchBar should not be alive!");
Assert.False(handlerReference.IsAlive, "Handler should not be alive!");
Assert.False(platformViewReference.IsAlive, "PlatformView should not be alive!");

Solved the issues by making a non-NSObject MauiSearchBarProxy class.

I found & fixed a couple related issues:

  • SearchBarExtensions.GetSearchTextField() would have always thrown StackOverlowException if iOS was less than 13? It just called itself?!?

  • Removed MauiSearchBar.EditingChanged, as we could subscribe to the event from the UITextField directly instead.

jonathanpeppers avatar Jul 26 '23 20:07 jonathanpeppers

This has UITest failures I haven't seen on other PRs, there must be a problem. Looking into it.

jonathanpeppers avatar Aug 04 '23 02:08 jonathanpeppers

@jonathanpeppers do you remember what was the test failure? now we have the uitests not working so can't trust these results.

rmarinho avatar Aug 21 '23 15:08 rmarinho

@rmarinho I was just going to come back to this one when UITests are working.

jonathanpeppers avatar Aug 21 '23 15:08 jonathanpeppers

This is green, but the UITests are disabled -- I am wondering if this actually breaks something, so will wait for UITests.

jonathanpeppers avatar Aug 28 '23 14:08 jonathanpeppers

@jonathanpeppers can you rebase main?! and i can run them for you to check. Main should be green for uitest right now, we will enable during this week

rmarinho avatar Aug 28 '23 15:08 rmarinho