Resolve DisposeRecursively crashed when we dispose scrollbase
authorEunki, Hong <eunkiki.hong@samsung.com>
Fri, 27 Oct 2023 09:47:55 +0000 (18:47 +0900)
committerEunki Hong <h.pichulia@gmail.com>
Tue, 31 Oct 2023 14:07:28 +0000 (23:07 +0900)
Due to some app's implements, ContentView can be disposed before ScrollBase
itself disposed. In this case, ContentView is not null.

So, when we try to call RemovePropertyNotification, it become crashed.

To avoid these cases, let we make DisposeRecursively API makes more safety.

And also, fix some crash issue in PerformanceTest1Page.xaml.cs what
can be problem in future.

Signed-off-by: Eunki, Hong <eunkiki.hong@samsung.com>
src/Tizen.NUI.Components/Controls/ScrollableBase.cs
src/Tizen.NUI/src/public/Common/Container.cs
test/NUITizenGallery/Examples/PerformanceTest/PerformanceTest1Page.xaml.cs

index 6ecd82d..b2cecd8 100755 (executable)
@@ -1388,7 +1388,10 @@ namespace Tizen.NUI.Components
                 mPanGestureDetector?.Dispose();
                 mPanGestureDetector = null;
 
-                ContentContainer?.RemovePropertyNotification(propertyNotification);
+                if(!(ContentContainer?.Disposed ?? true) && propertyNotification != null)
+                {
+                    ContentContainer?.RemovePropertyNotification(propertyNotification);
+                }
                 propertyNotification?.Dispose();
                 propertyNotification = null;
             }
index fdfbf2c..9c85ac4 100755 (executable)
@@ -18,6 +18,7 @@
 using System;
 using System.Collections.Generic;
 using System.ComponentModel;
+using System.Linq;
 using Tizen.NUI.BaseComponents;
 using Tizen.NUI.Binding;
 using Tizen.NUI.Binding.Internals;
@@ -249,18 +250,24 @@ namespace Tizen.NUI
         public void DisposeRecursively()
         {
             // To avoid useless "OnChildRemoved" callback invoke, Dispose itself before children.
-            if(!Disposed && !IsDisposeQueued)
+            if (!Disposed && !IsDisposeQueued)
             {
                 Dispose();
             }
 
-            foreach (View child in Children)
-            {
-                child.DisposeRecursively();
-            }
+            // Copy child referecen to avoid Children changed during DisposeRecursively();
+            var copiedChildren = childViews.ToList();
 
             // Make sure that itself don't have children anymore.
             childViews?.Clear();
+
+            foreach (View child in copiedChildren)
+            {
+                if (!(child?.Disposed ?? true))
+                {
+                    child.DisposeRecursively();
+                }
+            }
         }
 
         /// <summary>
index 2600777..4fb0efd 100644 (file)
@@ -98,8 +98,6 @@ namespace NUITizenGallery
 
         protected override void Dispose(DisposeTypes type)
         {
-            AppWindow.RemoveFrameUpdateCallback(FPSCounter);
-
             if (Disposed)
             {
                 return;
@@ -107,6 +105,7 @@ namespace NUITizenGallery
 
             if (type == DisposeTypes.Explicit)
             {
+                AppWindow.RemoveFrameUpdateCallback(FPSCounter);
                 RemoveAllChildren(true);
             }