Skip to content

Commit 3bfa4ac

Browse files
authored
Merge pull request #118 from redth-org/bugfix/gh-117-objectdisposed
Fix potential ObjectDisposeException when Window gets disposed while running cleanup
2 parents ab974b8 + 09f885a commit 3bfa4ac

File tree

3 files changed

+89
-10
lines changed

3 files changed

+89
-10
lines changed

BTProgressHUD/ProgressHUD.cs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ CAShapeLayer RingLayer
240240
bool IsClear => _maskType is MaskType.Clear or MaskType.None;
241241

242242
UIView OverlayView =>
243-
_overlayView ??= new UIView(HudWindow.Bounds)
243+
_overlayView ??= new UIView(HudWindow?.Bounds ?? CGRect.Empty)
244244
{
245245
AutoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleHeight,
246246
BackgroundColor = UIColor.Clear,
@@ -768,7 +768,17 @@ private void RemoveHud()
768768
_overlayView = null;
769769
RemoveFromSuperview();
770770

771-
HudWindow?.RootViewController?.SetNeedsStatusBarAppearanceUpdate();
771+
try
772+
{
773+
HudWindow?.RootViewController?.SetNeedsStatusBarAppearanceUpdate();
774+
}
775+
catch (ObjectDisposedException)
776+
{
777+
// Window was disposed while HUD cleanup was in progress.
778+
// This can happen in scenarios where the window gets disposed
779+
// during the dismiss animation. Since the HUD is being cleaned up anyway,
780+
// we can safely ignore this.
781+
}
772782
}
773783

774784
private void SetStatusWorker(string status)
@@ -817,14 +827,16 @@ private void PositionHUD(NSNotification? notification)
817827
{
818828
double animationDuration = 0;
819829

820-
Frame = HudWindow.Bounds;
830+
var windowBounds = HudWindow?.Bounds ?? CGRect.Empty;
831+
if (windowBounds.IsEmpty) return; // Window disposed, can't position
832+
Frame = windowBounds;
821833

822834
UIInterfaceOrientation orientation = UIInterfaceOrientation.Unknown;
823835

824-
if (!System.OperatingSystem.IsIOSVersionAtLeast(9) && !OperatingSystem.IsMacCatalystVersionAtLeast(9))
836+
if (!OperatingSystem.IsIOSVersionAtLeast(9) && !OperatingSystem.IsMacCatalystVersionAtLeast(9))
825837
orientation = UIApplication.SharedApplication.StatusBarOrientation;
826838

827-
bool ignoreOrientation = (System.OperatingSystem.IsIOSVersionAtLeast(8) || OperatingSystem.IsMacCatalystVersionAtLeast(8));
839+
bool ignoreOrientation = OperatingSystem.IsIOSVersionAtLeast(8) || OperatingSystem.IsMacCatalystVersionAtLeast(8);
828840

829841
var keyboardHeight = GetKeyboardHeightFromNotification(notification, ignoreOrientation, orientation, ref animationDuration);
830842

@@ -884,7 +896,7 @@ private void PositionHUD(NSNotification? notification)
884896
0, UIViewAnimationOptions.AllowUserInteraction, delegate
885897
{
886898
MoveToPoint(newCenter, rotateAngle);
887-
}, null);
899+
}, () => { });
888900
}
889901
else
890902
{

BTProgressHUDDemo/MainViewModel.cs

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public MainViewModel()
2424
Create("Cancel problem 3", () => BTProgressHUD.Show("Cancel", () => KillAfter(), "Cancel and text"), false),
2525
Create("Cancel problem 2", () => BTProgressHUD.Show("Cancel", () => KillAfter()), false),
2626
Create("Cancel problem", () => BTProgressHUD.Show("Cancel", () => KillAfter(), "This is a multilinetext\nSome more text\n more text\n and again more text"), false),
27-
Create("Show Message", () =>
27+
Create("Show Message", () =>
2828
BTProgressHUD.Show("Processing your image", 10, MaskType.Black), true),
2929
Create("Show Success", () =>
3030
{
@@ -103,7 +103,7 @@ public MainViewModel()
103103
{
104104
ProgressHUDAppearance.RingColor = UIColor.Green;
105105
ProgressHUDAppearance.RingBackgroundColor = UIColor.Brown;
106-
106+
107107
ProgressHUDAppearance.HudBackgroundColor = UIColor.Yellow;
108108
ProgressHUDAppearance.HudTextColor = UIColor.Purple;
109109
ProgressHUDAppearance.HudButtonTextColor = UIColor.Orange;
@@ -112,7 +112,74 @@ public MainViewModel()
112112
ProgressHUDAppearance.HudTextColor = UIColor.Cyan;
113113
ProgressHUDAppearance.HudToastBackgroundColor = UIColor.Blue;
114114
}, false),
115-
Create("Reset Customization", ProgressHUDAppearance.ResetToDefaults, false)
115+
Create("Reset Customization", ProgressHUDAppearance.ResetToDefaults, false),
116+
Create("GH117 ObjectDisposeException", async () => {
117+
try
118+
{
119+
// Test 1: Immediate disposal after show
120+
Console.WriteLine("Test 1: Immediate disposal after show");
121+
var window1 = new UIWindow(UIScreen.MainScreen.Bounds);
122+
window1.RootViewController = new UIViewController();
123+
window1.MakeKeyAndVisible();
124+
BTProgressHUD.Show(window1, "Test 1");
125+
window1.Dispose();
126+
await Task.Delay(100);
127+
BTProgressHUD.Dismiss(window1);
128+
129+
// Test 2: Disposal during dismiss animation
130+
Console.WriteLine("Test 2: Disposal during dismiss animation");
131+
var window2 = new UIWindow(UIScreen.MainScreen.Bounds);
132+
window2.RootViewController = new UIViewController();
133+
window2.MakeKeyAndVisible();
134+
BTProgressHUD.Show(window2, "Test 2");
135+
await Task.Delay(100);
136+
BTProgressHUD.Dismiss(window2);
137+
await Task.Delay(150); // Half way through 0.3s animation
138+
window2.Dispose();
139+
await Task.Delay(200); // Let animation complete
140+
141+
// Test 3: Rapid show/dismiss/dispose cycles
142+
Console.WriteLine("Test 3: Rapid cycles");
143+
for (int i = 0; i < 5; i++)
144+
{
145+
var window = new UIWindow(UIScreen.MainScreen.Bounds);
146+
window.RootViewController = new UIViewController();
147+
window.MakeKeyAndVisible();
148+
BTProgressHUD.Show(window, $"Rapid {i}");
149+
await Task.Delay(25);
150+
BTProgressHUD.Dismiss(window);
151+
await Task.Delay(25);
152+
window.Dispose();
153+
await Task.Delay(25);
154+
}
155+
156+
// Test 4: Force garbage collection
157+
Console.WriteLine("Test 4: Force GC");
158+
var window4 = new UIWindow(UIScreen.MainScreen.Bounds);
159+
window4.RootViewController = new UIViewController();
160+
window4.MakeKeyAndVisible();
161+
BTProgressHUD.Show(window4, "GC Test");
162+
window4 = null; // Remove reference
163+
GC.Collect();
164+
GC.WaitForPendingFinalizers();
165+
GC.Collect();
166+
await Task.Delay(100);
167+
// This might cause issues when dismiss tries to access the collected window
168+
169+
BTProgressHUD.Dismiss();
170+
Console.WriteLine("All tests completed without ObjectDisposedException");
171+
}
172+
catch (ObjectDisposedException ex)
173+
{
174+
Console.WriteLine($"SUCCESS: ObjectDisposedException reproduced! {ex.Message}");
175+
Console.WriteLine($"Stack trace: {ex.StackTrace}");
176+
}
177+
catch (Exception ex)
178+
{
179+
Console.WriteLine($"Other exception: {ex.GetType().Name}: {ex.Message}");
180+
Console.WriteLine($"Stack trace: {ex.StackTrace}");
181+
}
182+
}, false)
116183
];
117184
}
118185

build.cake

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
var target = Argument("target", "Default");
55
var configuration = Argument("configuration", "Release");
6-
var sln = new FilePath("./BTProgressHUD.sln");
6+
var sln = new FilePath("./BTProgressHUD/BTProgressHUD.csproj");
77
var artifactsDir = new DirectoryPath("./artifacts");
88
var gitVersionLog = new FilePath("./gitversion.log");
99

0 commit comments

Comments
 (0)