Partager via


Utilisation du thread d’interface utilisateur dans Xamarin.iOS

Les interfaces utilisateur d’application sont toujours à thread unique, même dans les appareils multithreads , il n’existe qu’une seule représentation de l’écran et toutes les modifications apportées à ce qui est affiché doivent être coordonnées via un seul « point d’accès ». Cela empêche plusieurs threads d’essayer de mettre à jour le même pixel en même temps (par exemple).

Votre code doit uniquement apporter des modifications aux contrôles d’interface utilisateur à partir du thread principal (ou de l’interface utilisateur). Toutes les mises à jour de l’interface utilisateur qui se produisent sur un autre thread (tel qu’un rappel ou un thread d’arrière-plan) peuvent ne pas être rendues à l’écran, ou peuvent même entraîner un blocage.

Exécution du thread d’interface utilisateur

Lorsque vous créez des contrôles dans une vue ou que vous gérez un événement initié par l’utilisateur, tel qu’une interaction tactile, le code s’exécute déjà dans le contexte du thread d’interface utilisateur.

Si le code s’exécute sur un thread d’arrière-plan, dans une tâche ou un rappel, il est probable qu’il ne s’exécute pas sur le thread d’interface utilisateur principal. Dans ce cas, vous devez encapsuler le code dans un appel à InvokeOnMainThread ou BeginInvokeOnMainThread comme suit :

InvokeOnMainThread ( () => {
    // manipulate UI controls
});

La InvokeOnMainThread méthode est définie pour NSObject qu’elle puisse être appelée à partir de méthodes définies sur n’importe quel objet UIKit (tel qu’un view ou un contrôleur de vue).

Lors du débogage d’applications Xamarin.iOS, une erreur est générée si votre code tente d’accéder à un contrôle d’interface utilisateur à partir du thread incorrect. Cela vous permet de suivre et de résoudre ces problèmes avec la méthode InvokeOnMainThread. Cela se produit uniquement pendant le débogage et ne lève pas d’erreur dans les builds de mise en production. Le message d’erreur s’affiche comme suit :

Exécution du thread d’interface utilisateur

Exemple de thread d’arrière-plan

Voici un exemple qui tente d’accéder à un contrôle d’interface utilisateur (a UILabel) à partir d’un thread d’arrière-plan à l’aide d’un thread simple :

new System.Threading.Thread(new System.Threading.ThreadStart(() => {
    label1.Text = "updated in thread"; // should NOT reference UILabel on background thread!
})).Start();

Ce code lève le UIKitThreadAccessException débogage pendant le débogage. Pour résoudre le problème (et vérifier que le contrôle d’interface utilisateur est accessible uniquement à partir du thread d’interface utilisateur principal), encapsulez tout code qui référence les contrôles d’interface utilisateur à l’intérieur d’une InvokeOnMainThread expression comme suit :

new System.Threading.Thread(new System.Threading.ThreadStart(() => {
    InvokeOnMainThread (() => {
        label1.Text = "updated in thread"; // this works!
    });
})).Start();

Vous n’aurez pas besoin de l’utiliser pour le reste des exemples de ce document, mais il est important de se rappeler quand votre application effectue des requêtes réseau, utilise le centre de notification ou d’autres méthodes qui nécessitent un gestionnaire d’achèvement qui s’exécutera sur un autre thread.

Exemple Async/Await

Lorsque vous utilisez l’async/await C# 5 mot clé s InvokeOnMainThread n’est pas nécessaire, car lorsqu’une tâche attendue termine la méthode continue sur le thread appelant.

Cet exemple de code (qui attend sur un appel de méthode Delay, purement à des fins de démonstration) affiche une méthode asynchrone appelée sur le thread d’interface utilisateur (il s’agit d’un gestionnaire TouchUpInside). Étant donné que la méthode conteneur est appelée sur le thread d’interface utilisateur, les opérations d’interface utilisateur telles que la définition du texte sur un ou l’affichage d’une UILabelUIAlertView méthode peuvent être appelées en toute sécurité une fois les opérations asynchrones terminées sur les threads d’arrière-plan.

async partial void button2_TouchUpInside (UIButton sender)
{
    textfield1.ResignFirstResponder ();
    textfield2.ResignFirstResponder ();
    textview1.ResignFirstResponder ();
    label1.Text = "async method started";
    await Task.Delay(1000); // example purpose only
    label1.Text = "1 second passed";
    await Task.Delay(2000);
    label1.Text = "2 more seconds passed";
    await Task.Delay(1000);
    new UIAlertView("Async method complete", "This method", 
               null, "Cancel", null)
        .Show();
    label1.Text = "async method completed";
}

Si une méthode asynchrone est appelée à partir d’un thread d’arrière-plan (et non du thread d’interface utilisateur principal), il InvokeOnMainThread est toujours nécessaire.