Bug 17588 - App crashes when shown UIAlertView which did handled Dismissed event by DispatchAsync.
Summary: App crashes when shown UIAlertView which did handled Dismissed event by Dispa...
Status: RESOLVED FEATURE
Alias: None
Product: iOS
Classification: Xamarin
Component: XI runtime ()
Version: 7.0.6.x
Hardware: Macintosh Mac OS
: Normal normal
Target Milestone: Untriaged
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2014-02-04 04:36 UTC by Ryoji.Ishikawa
Modified: 2014-02-10 10:58 UTC (History)
4 users (show)

Tags:
Is this bug a regression?: ---
Last known good build:


Attachments
Sample code (6.32 KB, application/zip)
2014-02-04 20:29 UTC, Ryoji.Ishikawa
Details


Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on Developer Community or GitHub with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED FEATURE

Description Ryoji.Ishikawa 2014-02-04 04:36:38 UTC
App crashes when shown UIAlertView which did handled the Dismissed event by DispatchAsync.

I'm using,
 Xamarin.iOS: 7.0.6.128(Business Edition)
 Xcode: 5.0.2(3335.32)
 Xamarin Studio: 4.2.2(build2)

Target OS version is 6.1 and 7.0.
Simulator and Device has same issue.

Test Code
--------------------------------------------------------------------
void AAA()
{
    using (UIAlertView alert = new UIAlertView())
    {
        alert.Message = "Test";
        alert.AddButton("OK");
        alert.Dismissed += delegate
        {
        };
        alert.Show();
    }
}

void Test()
{
    DispatchQueue.GetGlobalQueue(DispatchQueuePriority.Low).DispatchAsync(delegate
    {
        DispatchQueue.MainQueue.DispatchAsync(delegate ()
        {
            AAA();
        });
    });
}
--------------------------------------------------------------------
Comment 1 Sadik Ali 2014-02-04 06:15:10 UTC
I checked this issue but I am getting error "DispatchQueue does not exist in the current context"

Please suggest me what assembly I need to include for this error.
Comment 2 Ryoji.Ishikawa 2014-02-04 20:29:48 UTC
Created attachment 5974 [details]
Sample code
Comment 3 Ryoji.Ishikawa 2014-02-04 20:30:06 UTC
I attached sample code.
Sample code has 3 test patterns.

-Test1 and Test2
 UIAlartView is shown. And then when you tapped button in UIAlartView, App is crashes.

-Test3
 App clashes without displaying UIAlartView.
Comment 4 Ryoji.Ishikawa 2014-02-04 21:45:43 UTC
Sorry, My sample code does not have the issue on Device.
Only the Simulator has this issue.
Comment 5 Sadik Ali 2014-02-05 02:59:58 UTC
I am able to reproduce this issue on below environment using simulator:

All Mac
XS 4.2.2(build 2)
X iOS 7.0.6.168 


Refer screen cast: http://www.screencast.com/t/m7rOd0otfQ7
Comment 6 Sebastien Pouliot 2014-02-05 09:43:51 UTC
This is not a bug. Your code is effectively disposing the UIAlertView (because of the using) before it gets dismissed.

Step over each line using the debugger and you'll see that you're calling Dispose before you actually dismiss the UIAlertView.

You can also see this easily by adding a Console.WriteLine after your dispose. E.g.

			using (UIAlertView alert = new UIAlertView())
			{
				alert.Message = "TEST";
				alert.AddButton("OK");
				alert.Dismissed += delegate
				{
				};
				alert.Show();
			}
                        // implicit Dispose here
			Console.WriteLine ("alert (UIAlertView) was disposed - GC can collect it");

^ that C.WL will be printed *before* you dismiss (because Show is async, not blocking, and control gets back to your code immediately).

That means the event you set (for `Dismissed`) has been potentially [1] been collected and the (native) control tries to go back to managed code (that has been freed) and will crash.

A common solution is to promote your `alert` from a local variable to a field (see bug #17533) and not to dispose it until you know it's not used anymore (e.g. when that View gets disposed). That field will ensure a reference is kept to the (managed) instance of UIAlertView and the GC won't be allowed to collect it.

Another option is to make the the Show call "blocking" and let the GC collect it (do not dispose it manually). Here's a nice helper method [2] to do this. 

[1] on the iOS simulator we're running the GC much more often to help find such issues. IOW it would happen on devices too - it just would look like a lot more random (and harder to diagnose/fix).

[2] http://stackoverflow.com/a/19162207
Comment 7 Ryoji.Ishikawa 2014-02-10 03:20:27 UTC
Thank you for your support.
Comment 8 Miguel de Icaza [MSFT] 2014-02-10 10:58:34 UTC
I love this approach at using UIAlertView personally:

http://stackoverflow.com/questions/19120841/yes-no-confirmation-uialertview