Xamarin IOS 无法创建控制器异步任务

Xamarin IOS can't create controller async task

我会尽力用英语来解释这个问题。 我目前正在尝试使用 Xamarin 来检查我们是否会在此基础上迁移我们的 IOS 应用程序和 Android 应用程序,因为它看起来真的很不错。

我做的小测试只是测试我的简单登录页面。

我是 CSharp 的新手,如果我提出愚蠢和简单的问题,请提前道歉...

先介绍实现,再介绍问题post。

[实施]

这就是我使用 nuggets 的 RestSharp (Rest library client) 库所做的。我有一个共享项目,将在 Android 应用程序和 IOs 应用程序中使用(以便仅完成一次工作)。我正在 Mac.

上使用 Xamarin Studio

在我的 LoginApiManager.cs 中,我有一个这样的 "basic" 实现:

public interface UserConnectionStates
    {
        //Regroup all state created above
        void userIsConnected(User user);
        void userConnectionFailed(IRestResponse<User> response);
        void userDisconnected();
}

public class LoginApiManager : RestManager
{
    //Used for instance and shared element
    public static LoginApiManager instance;

    //Permits to store the information about the current loged in user
    private User loggedInUser;

    //All listeners for that class
    private List<UserConnectionStates> userConnectionStatesListeners = new List<UserConnectionStates>();

    public LoginApiManager()
    {
        //Create the the Rest Client to make Api Calls
        base.client = new RestClient();
        client.BaseUrl = new Uri(apiPath);
        client.Authenticator = new HttpBasicAuthenticator(null, null);
    }

    public static LoginApiManager getInstance()
    {
        if (instance != null)
        {
            return instance;
        }
        else
        {
            return new LoginApiManager();
        }
    }

    //------- UserConnectionStates Listeners accessors --------
    public void addUserConnectionStatesListener(UserConnectionStates listener)
    {

        if (!userConnectionStatesListeners.Contains(listener))
        {
            userConnectionStatesListeners.Add(listener);
        }

    }

    public void removeUserConnectionStatesListener(UserConnectionStates listener)
    {
        if (userConnectionStatesListeners.Contains(listener))
        {
            userConnectionStatesListeners.Remove(listener);
        }
    }

    /*
     * Permits to connect a user with a given username and password. It will
     * call the API and return a User Object containing all information needed
     * for connection, including token.
     */
    public void connectUserWithUserNameAndPassword(string username, string password)
    {

        var request = new RestRequest(Method.POST);
        request.Resource = "/myApiEndpoints/";

        //Add it to the request
        request.AddParameter("username", username);
        request.AddParameter("password", password);

        //Execute the query
        client.ExecuteAsync<User>(request, (response) =>
        {
            if (response.StatusCode == System.Net.HttpStatusCode.OK)
            {
                //We serialize the user from response
                loggedInUser = response.Data;
                foreach (var l in this.userConnectionStatesListeners)
                {
                    l.userIsConnected(response.Data);
                }

            }
            else
            {
                //We send error to the code
                foreach(var l in this.userConnectionStatesListeners)
                {
                    l.userConnectionFailed(response);
                }
            }

        });
    }
}

...好的,让我们继续,我的 LoginViewController 实现接口 UserConnectionStates 并将自己引用到侦听器列表,以便了解不同的连接状态修改。就像这样:

在我的 LoginController.cs

public partial class LoginController : UIViewController, UserConnectionStates
{
    //Some code here ...

    public override void ViewDidLoad()
    {
        base.ViewDidLoad();
        loginManager = LoginApiManager.getInstance();
        loginManager.addUserConnectionStatesListener(this); //we create a listener for information about user connection

    }

    //Here comme the interface methods...

    //Interface for listening user connection state
    public void userIsConnected(User user)
    {
        var alertController = UIAlertController.Create("Connexion", "Connexion Success!",UIAlertControllerStyle.Alert);
        alertController.AddAction(UIAlertAction.Create("OK", UIAlertActionStyle.Cancel, null));
        this.PresentViewController(alertController, true, null);

    }

    public void userConnectionFailed(IRestResponse<User> response)
    {
        var alert= UIAlertController.Create("Connexion",  "Unable to connect", UIAlertControllerStyle.Alert);
        alert.AddAction(UIAlertAction.Create("OK", UIAlertActionStyle.Cancel, null));
        PresentViewController(alert, animated: true, completionHandler: null);
    }

    public void userDisconnected()
    {

    }

}

[问题]

...这是我的问题,当 client.ExecuteAsync(request, (response)) 被调用时,作为成功的例子,它会调用由我的 LoginController 的侦听器对象 public void userIsConnected(User user) 实现的接口方法,但是因为它是在另一个线程中调用的,所以它在

处停止
 var alertController = UIAlertController.Create("Connexion", "Connexion Success!",UIAlertControllerStyle.Alert);

nos 崩溃只是停止而不做任何事情。

我用一个简单的

做了个测试
IRestResponse response = client.Execute(request); 

它之所以有效,是因为该方法是同步的并在同一个线程中调用,但它会锁定 UI 直到任务完成...

在 CSharp 或 Xamarin 中实现这种模式的最佳方式是什么?如果有另一种方法可以做这样的事情,我会学习它,但是因为我是新手,所以我不知道这种事情的最佳实践是什么,而且我没有在文档中找到这个(它是肯定在里面,但不要觉得抱歉)。

老实说,我会重新考虑您当前的代码结构。首先,我会停止使用 RestSharp 并选择:Refit

这是一个非常酷的 post,它可以阐明如何正确构建代码:Mobile resiliency with Xamarin

在您的 iOS 和 Android 应用程序中使用 MVVM。这样您就可以共享 ViewModel 并拥有更多可重用和分离的代码。