From 135963784858845f22eacbfc16e235817221430c Mon Sep 17 00:00:00 2001 From: Jerome Laban Date: Thu, 30 Nov 2023 17:14:35 -0500 Subject: [PATCH] fix: Provide the ability to break on invalid calls to `NSObjectExtensions.ValidateDispose` --- doc/articles/feature-flags.md | 6 +++ .../Extensions/NSObjectExtensions.iOS.cs | 53 +++++++++++-------- src/Uno.UI/FeatureConfiguration.cs | 5 ++ 3 files changed, 42 insertions(+), 22 deletions(-) diff --git a/doc/articles/feature-flags.md b/doc/articles/feature-flags.md index f87196c7d19a..5967e45ae7ce 100644 --- a/doc/articles/feature-flags.md +++ b/doc/articles/feature-flags.md @@ -102,3 +102,9 @@ It is also possible to adjust the delay in milliseconds (`Uno.UI.FeatureConfigur ## `ApplicationData` On GTK and WPF it is possible to override the default `ApplicationData` folder locations using `WinRTFeatureConfiguration.ApplicationData` properties. For more information see [related docs here](/articles/features/applicationdata.md#data-location-on-gtk-and-wpf) + +## Deprecated NSObjectExtensions.ValidateDispose for iOS + +The method `NSObjectExtensions.ValidateDispose` is deprecated in Uno 5.x and will be removed in the next major release. + +In order for calls to fail on uses of this method, set the `Uno.UI.FeatureConfiguration.UIElement.FailOnNSObjectExtensionsValidateDispose` flag to `true`. diff --git a/src/Uno.UI/Extensions/NSObjectExtensions.iOS.cs b/src/Uno.UI/Extensions/NSObjectExtensions.iOS.cs index 0b64abc8b5bc..32a1039e7564 100644 --- a/src/Uno.UI/Extensions/NSObjectExtensions.iOS.cs +++ b/src/Uno.UI/Extensions/NSObjectExtensions.iOS.cs @@ -6,45 +6,54 @@ using Foundation; using UIKit; using CoreGraphics; +using Uno.UI; namespace Foundation { public static class NSObjectExtensions { /// - /// Validates the call to the Dispose method. + /// THIS METHOD IS DEPRECATED. DO NOT USE IT. + /// It will be removed in the next major version. /// /// The view to be disposed. /// True if called from View.Dispose, False if called from the finalizer. /// True if the dispose method can continue executing, otherwise, false. - /// This method will requeue the call to Dispose on the UIThread if called from the finalizer. + /// Validates the call to the Dispose method. This method will requeue the call to Dispose on the UIThread if called from the finalizer. public static bool ValidateDispose(this NSObject view, bool disposing) { - if (!disposing) + if (FeatureConfiguration.UIElement.FailOnNSObjectExtensionsValidateDispose) { - view.Log() - .ErrorFormat( - "The instance {0}/{1:X8} has not been disposed properly, re-scheduling. This usually indicates that the creator of this view did not dispose it properly.", - view.GetType(), - view.Handle - ); + throw new InvalidOperationException($"NSObjectExtensions.ValidateDispose has been disabled. Remove any invocation to this method, it does not need to replaced by anything else."); + } + else + { + if (!disposing) + { + view.Log() + .ErrorFormat( + "The instance {0}/{1:X8} has not been disposed properly, re-scheduling. This usually indicates that the creator of this view did not dispose it properly.", + view.GetType(), + view.Handle + ); - // Make sure the instance is kept alive - GC.ReRegisterForFinalize(view); + // Make sure the instance is kept alive + GC.ReRegisterForFinalize(view); - // We cannot execute the content of the dispose actions off of the UI Thread. - // So we reschedule the dispose on the UI Thread to avoid concurrency issues. - _ = CoreDispatcher.Main.RunIdleAsync(_ => - { + // We cannot execute the content of the dispose actions off of the UI Thread. + // So we reschedule the dispose on the UI Thread to avoid concurrency issues. + _ = CoreDispatcher.Main.RunIdleAsync(_ => + { - view.Dispose(); - }); + view.Dispose(); + }); - return false; - } - else - { - return true; + return false; + } + else + { + return true; + } } } } diff --git a/src/Uno.UI/FeatureConfiguration.cs b/src/Uno.UI/FeatureConfiguration.cs index 3a27f095c64d..d103c39361d2 100644 --- a/src/Uno.UI/FeatureConfiguration.cs +++ b/src/Uno.UI/FeatureConfiguration.cs @@ -656,6 +656,11 @@ public static class UIElement /// This defaults to false, which prevents the specific event instead of calling CompleteGesture /// public static bool DisablePointersSpecificEventPrevention { get; set; } + + /// + /// Enables failure when is invoked. + /// + public static bool FailOnNSObjectExtensionsValidateDispose { get; set; } } public static class VisualState