调用 iOS Alert 时出现 UI 一致性错误

Posted

技术标签:

【中文标题】调用 iOS Alert 时出现 UI 一致性错误【英文标题】:UI consistency error when calling iOS Alert 【发布时间】:2016-05-11 20:04:39 【问题描述】:

我有一个 ios Xamarin 项目,但出现以下错误:

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

以下代码会出现此错误:

在我的欢迎视图页面中,我有一个名为 SyncButton 的按钮被点击。单击该按钮应该使用 REST 与服务器同步数据。

在我的 WelcomeController 中有:

....
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);

    

当确实存在超时或其他错误时,应该会发出警报。

SyncButtonCore() 包含在一个如下所示的委托类中:

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);

我的RequestWithAlert 班级在哪里:

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);
         

最后一段代码中的 NativeAlert() 函数出现错误。这最终引发了在我的代码开头提到的 UIKit 错误

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

我不确定我在这里做错了什么以及为什么我不允许创建此警报,因为我在 WelcomeController 中定义了它,而我的 UIThread 应该是正确的?

【问题讨论】:

您的网络操作将在后台线程上完成。您需要在主/UI 线程中显式执行您的 UI 操作。 @Paulw11 谢谢,用InvokeOnMainThread 包围了这个技巧 @user3470987 如果您发布一个显示您如何使用InvokeOnMainThread 的答案,它可能会帮助一些人。 【参考方案1】:

问题出在我的iOSErrorAlert() 函数中。我需要用 InvokeOnMainThread() 包围它,因为 UI 操作应该在主线程中执行(我没有这样做,因为我将它传递给其他类/线程)。感谢@Paulw11 的评论。

不得不替换这个:

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);

有了这个:

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);
    );

【讨论】:

以上是关于调用 iOS Alert 时出现 UI 一致性错误的主要内容,如果未能解决你的问题,请参考以下文章

“调用线程无法访问此对象,因为不同的线程拥有它”从 WPF 中的不同线程更新 UI 控件时出现错误

在 iOS 上调用“fetch”时出现 Javascript“TypeError:cancelled”错误

将套接字从电子 UI 连接到 python 服务器时出现错误 400(错误请求)

为啥当我尝试在 ios 7.1 sdk、xcode 5.1 中调用 deallocate 或 release 时出现错误?

为 iOS 构建 OCUnit 应用程序测试目标时出现链接器错误

Grafana Alert/AzureMonitor:在 Grafana 中为图形创建警报规则时出现执行错误