简体   繁体   中英

UI consistency error when calling iOS Alert

I have an iOS Xamarin project were I am getting the following error:

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

This error occurs with the following code:

In my Welcome view page I have a button called SyncButton that gets clicked. This click of the button is supposed to sync data with a server using REST.

In my WelcomeController I have:

....
SyncButton.TouchUpInside += async (object sender, EventArgs e) => {
            SyncButton.Enabled = false;

            await welcomeDelegate.syncButtonCore (cred, iOSErrorAlert);

            SyncButton.Enabled = true;
        };
 ....

public void iOSErrorAlert(string LoginErrorTitle, string LoginErrorMessage){
        var Alert = UIAlertController.Create (LoginErrorTitle, LoginErrorMessage, UIAlertControllerStyle.Alert);
        Alert.AddAction (UIAlertAction.Create ("OK", UIAlertActionStyle.Cancel, null));
        PresentViewController (Alert, animated: true, completionHandler: null);

    }

Alerts should happen when there is a timeout or some other error really.

The SyncButtonCore() is contained in a delegate class that looks like this:

public async Task syncButtonCore(UserCredentials cred, RequestWithAlertDelegate.ErrorAlert NativeAlert){
        await Task.Run (async ()=>{
            RequestWithAlertDelegate requestWithAlert = new RequestWithAlertDelegate();
            string URL = URLs.BASE_URL + URLs.CASELOAD + "/" + cred.PID;
            await requestWithAlert.RequestWithRetry(URL, cred.UserID, cred.Password, NativeAlert, null, async delegate (string Response1){...}, 1);

Where my RequestWithAlert class is:

public async Task RequestWithRetry (string URL, string UserID, string Password, ErrorAlert NativeAlert, SyncAction Action, AsyncAction Action2, int times)
    {
        ...make sure legit credentials...
        if (LoginError) {
            NativeAlert (LoginErrorTitle, LoginErrorMessage);
        } 

Where I am getting my error at the NativeAlert() function in that last bit of code. Which ultimately throws the UIKit error mentioned at the beginning in my code at

var Alert = UIAlertController.Create (LoginErrorTitle, LoginErrorMessage, UIAlertControllerStyle.Alert);

I'm not sure what I am doing wrong here and why I am not allowed to create this alert because I define it in my WelcomeController which is where my UIThread should be correct?

Problem was in my iOSErrorAlert() function. I needed to surround it with the InvokeOnMainThread() because UI actions should be performed in the main thread (which I was not doing because I was passing it around to other classes/threads). Thank you @Paulw11 for the comment.

Had to replace this:

public void iOSErrorAlert(string LoginErrorTitle, string LoginErrorMessage){
    var Alert = UIAlertController.Create (LoginErrorTitle, LoginErrorMessage, UIAlertControllerStyle.Alert);
    Alert.AddAction (UIAlertAction.Create ("OK", UIAlertActionStyle.Cancel, null));
    PresentViewController (Alert, animated: true, completionHandler: null);
}

With this:

public void iOSErrorAlert(string LoginErrorTitle, string LoginErrorMessage){
    InvokeOnMainThread (() => {
        var Alert = UIAlertController.Create (LoginErrorTitle, LoginErrorMessage, UIAlertControllerStyle.Alert);
        Alert.AddAction (UIAlertAction.Create ("OK", UIAlertActionStyle.Cancel, null));
        PresentViewController (Alert, animated: true, completionHandler: null);
    });
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM