2017-02-23 3 views
1

Tout travail lié à l'interface utilisateur doit être exécuté sur le thread principal pour iOS. Parfois, nous devons faire des emplois async comme le téléchargement d'une image et nous utiliserions probablement dispatch_async et quand le téléchargement terminé nous obtenons le thread principal et l'afficher comme quelque chose comme ceci:Les méthodes uikit sont-elles garanties sur le thread principal?

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ 
UIImage *overlayImage = [self faceOverlayImageFromImage:_image]; 
dispatch_async(dispatch_get_main_queue(), ^{ 
    [self fadeInNewImage:overlayImage]; 
}); 

});}

Mais quand on charge une image que nous faisons habituellement juste localement cela sans l'envoi sur fil conducteur:

UIImageView *imageView = [[UIImageView alloc] initWithImage:@"myimage.png"]; 

Ma question est qu'ils sont garantis pour être exécuté sur thread principal? Si oui, pourquoi devrions-nous l'envoyer en utilisant dispatch_get_main_queue()? Si non, pourquoi n'avons-nous pas besoin d'envoyer tous les travaux liés à ui sur le thread principal?

Répondre

6

Vous êtes confus.

Une chaîne d'appel donnée est exécutée sur le thread principal ou sur un thread d'arrière-plan. La majeure partie du code que vous traitez est invoquée par le biais d'événements système et est garantie d'être exécutée sur le thread principal. Il y a seulement un nombre limité de cas où votre code sera invoqué à partir d'un thread d'arrière-plan. Seulement dans ces cas avez-vous besoin d'emballer les appels UIKit dans le code qui redirige l'appel vers le thread principal.

Les fonctions du contrôleur, les actions des touches, etc. sont toujours appelées sur le thread principal. Si le système appelle une méthode sur un thread d'arrière-plan, il sera bien documenté.

Certaines fonctions prenant des gestionnaires d'achèvement invoquent ces gestionnaires d'achèvement sur un thread d'arrière-plan. La classe NSURLSession (URLSession), par exemple, appelle ses gestionnaires d'achèvement et ses méthodes déléguées dans une file d'attente déléguée par défaut à un thread d'arrière-plan. Ainsi, lorsque vous passez un gestionnaire d'achèvement à une instance de URLSession, vous devez vous assurer que votre code UIKit est enveloppé dans un appel à dispatch_async() (DispatchQueue.main.async() dans Swift 3) ou une méthode similaire de passage de code au thread principal à exécuter.

+0

Pour clarifier: le plus souvent, la raison pour laquelle vous devez utiliser dispatch est que * vous * avez démarré un thread d'arrière-plan, et que ce thread doit modifier l'interface utilisateur. À moins que la modification de l'interface utilisateur ne soit effectuée via un rappel qui gère le basculement vers le thread d'interface utilisateur pour vous (par exemple, setProgress d'une barre de progression), vous devez utiliser dispatch. – ToolmakerSteve

1

La plupart des actions liées à l'interface utilisateur doivent être exécutées sur le thread principal pour qu'elles fonctionnent correctement. Mais simplement en utilisant une classe UI... ne fait rien pour s'assurer qu'il est exécuté sur le thread principal.

C'est votre travail en tant que programmeur. Si vous faites quelque chose (comme télécharger des données ou effectuer une longue tâche) en arrière-plan et que vous devez ensuite mettre à jour l'interface utilisateur, vous devez vous assurer que le code de l'interface utilisateur est exécuté sur le thread principal. Gardez à l'esprit que créer UIImage instances peut être créé en toute sécurité sur un thread d'arrière-plan. C'est sûr.

tl; dr - non, rien n'est garanti pour être exécuté sur le thread principal. Et vous devez distribuer chaque travail lié à l'interface utilisateur sur le thread principal, sauf si vous êtes déjà sur le thread principal.