-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[ios] fix memory leaks in MauiDoneAccessoryView (#16380)
Context: #16346 This addresses the memory leak discovered by: src/Core/src/Platform/iOS/MauiDoneAccessoryView.cs(11,19): error MA0002: Member '_doneClicked' could cause memory leaks in an NSObject subclass. Remove the member, store the value as a WeakReference, or add the [UnconditionalSuppressMessage("Memory", "MA0002")] attribute with a justification as to why the member will not leak. After writing a test for it, I found a pattern the analyze doesn't currently catch: public MauiDoneAccessoryView(Action doneClicked) { //... var doneButton = new UIBarButtonItem(UIBarButtonSystemItem.Done, OnClicked); SetItems(new[] { spacer, doneButton }, false); } This creates a cycle: * `MauiDoneAccessoryView` -> `UIBarButtonItem` via list of items * `UIBarButtonItem` -> `Action` -> `MauiDoneAccessoryView` via `OnClicked` `MauiDoneAccessoryView` lives forever, as well as the owners of any `Action` delegate values passed in. I could resolve these problems by creating a new non-NSObject `BarButtonItemProxy` type to handle events. This solves one leak with the following controls that use `MauiDoneAccessoryView`: * `Editor` * `Picker` * `DatePicker` * `TimePicker` However, I'll need to send future PRs to verify all these controls are 100% leak free.
- Loading branch information
1 parent
e642faf
commit a8cda9d
Showing
3 changed files
with
87 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
using System; | ||
using System.Threading.Tasks; | ||
using Xunit; | ||
|
||
#if IOS || MACCATALYST | ||
|
||
namespace Microsoft.Maui.DeviceTests.Memory | ||
{ | ||
// Set of tests to verify UIView subclasses do not leak | ||
[Category(TestCategory.Memory)] | ||
public class UIViewSubclassTests : TestBase | ||
{ | ||
#if IOS // MauiDoneAccessoryView is iOS only | ||
void DoAction() { } | ||
void DoAction(object data) { } | ||
|
||
[Fact] | ||
public async Task MauiDoneAccessoryView_Ctor() | ||
{ | ||
WeakReference reference = null; | ||
Action action = DoAction; | ||
|
||
await InvokeOnMainThreadAsync(() => | ||
{ | ||
var accessory = new MauiDoneAccessoryView(action); | ||
reference = new(accessory); | ||
}); | ||
|
||
await AssertionExtensions.WaitForGC(reference); | ||
Assert.False(reference.IsAlive, "MauiDoneAccessoryView should not be alive!"); | ||
} | ||
|
||
[Fact] | ||
public async Task MauiDoneAccessoryView_SetDoneClicked() | ||
{ | ||
WeakReference reference = null; | ||
Action<object> action = DoAction; | ||
|
||
await InvokeOnMainThreadAsync(() => | ||
{ | ||
var accessory = new MauiDoneAccessoryView(); | ||
reference = new(accessory); | ||
accessory.SetDoneClicked(action); | ||
}); | ||
|
||
await AssertionExtensions.WaitForGC(reference); | ||
Assert.False(reference.IsAlive, "MauiDoneAccessoryView should not be alive!"); | ||
} | ||
#endif | ||
} | ||
} | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters