Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writing async monotouch code

So I have a method that must execute three tasks. The first task must be completed before the other two, which can be executed in parallel. This is what I have right now (modified for simplicity)

void facebookButtonClicked (object sender, EventArgs e)
        {
            View.Add (loadingOverlay);
            AppDelegate.MobileService = new MobileServiceClient ("myserverUrl", "myApiKey");
            var users= AppDelegate.MobileService.GetTable<User> ();
            var identities= AppDelegate.MobileService
                .GetTable ("Identities");
            AppDelegate.MobileService
                .LoginAsync (this, MobileServiceAuthenticationProvider.Facebook)
                    .ContinueWith (t => {
                if (t.Status == TaskStatus.RanToCompletion) {
                            AppDelegate.mobileServiceUser = t.Result;
                            var task1 = users.InsertAsync(new User{BirthDate = DateTime.Now});
                            var task2 = identities.ReadAsync("");
                            Task.Factory.ContinueWhenAll(new Task[]{task1,task2},_=>{
                                if(task1.Status==TaskStatus.RanToCompletion && task2.Status== TaskStatus.RanToCompletion)
                                {
                                    var token = task2.Result
                                        .GetArray()[0]
                                        .GetObject ()
                                        .GetNamedObject ("identities")
                                        .GetNamedObject ("facebook")
                                        .GetNamedString ("accessToken");    

                                SaveAuthorization (token);
                                NavigationController.PushViewController (new TabBarController (), false);
                                }
                            });             
                        }});
        }

The problem is (other than Im a newb at async code) that when it tries to execute "PushViewController" I get:

UIKit.UIKitThreadAccessException: UIKit Consistency error: you are calling a UIKit method that can only be invoked from the UI thread

How can I refactor/modify this code to fix it? please help.

like image 650
nacho10f Avatar asked Nov 29 '22 08:11

nacho10f


2 Answers

I call InvokeOnMainThread and use an anonymous function in my asynchronous methods.

InvokeOnMainThread(() => {  
    NavigationController.PushViewController (new TabBarController(), false);
});

If for some reason you are in a static class (like I was), you can do this

new NSObject().InvokeOnMainThread(() => {   
    NavigationController.PushViewController (new TabBarController(), false);
});
like image 119
valdetero Avatar answered Dec 30 '22 13:12

valdetero


Take a look at InvokeOnMainThread or BeginInvokeOnMainThread

http://docs.xamarin.com/ios/Guides/Advanced_Topics/Threading#Developing_Responsive_Applications

NavigationController.BeginInvokeOnMainThread (delegate { 
    NavigationController.PushViewController (new TabBarController (), false);
}); 
like image 32
holmes Avatar answered Dec 30 '22 13:12

holmes