J'utilise DispatchQueue.main.async depuis longtemps pour effectuer certaines opérations liées à l'interface utilisateur. Mais Swift fournit DispatchQueue.main.async et DispatchQueue.main.sync et les deux sont exécutés dans la file d'attente principale. Alors, est-ce que quelqu'un peut me dire la différence entre eux? Et quand devrais-je les utiliser? Merci d'avance.
DispatchQueue.main.async {
self.imageView.image = imageView
self.lbltitle.text = ""
}
DispatchQueue.main.sync {
self.imageView.image = imageView
self.lbltitle.text = ""
}
Pourquoi la simultanéité Dès que vous ajoutez des tâches lourdes à votre application, comme le chargement de données, le travail de votre interface utilisateur est ralenti ou même bloqué. La simultanéité vous permet d'effectuer 2 tâches ou plus "simultanément". L'inconvénient de cette approche est que la sécurité du fil n'est pas toujours aussi facile à contrôler. F.e. lorsque différentes tâches veulent accéder aux mêmes ressources, par exemple essayer de modifier la même variable sur des threads différents ou d'accéder aux ressources déjà bloquées par les différents threads.
Il y a quelques abstractions dont nous devons être conscients.
Files d'attente .
Doit être série ou concurrente . Ainsi que global ou privé en même temps.
Avec les files d'attente en série, les tâches seront terminées une à une, tandis qu'avec les files d'attente simultanées, les tâches seront exécutées simultanément et seront terminées selon des planifications inattendues. Le même groupe de tâches prendra plus de temps sur une file d'attente série par rapport à une file d'attente simultanée.
Vous pouvez créer vos propres files d'attente privées (à la fois série ou concurrent) ou utiliser déjà disponibles files d'attente globales (système) . La file d'attente principale est la seule file d'attente série parmi toutes les files d'attente globales.
Il est fortement recommandé de ne pas effectuer de tâches lourdes ne faisant pas référence à des travaux d'interface utilisateur sur la file d'attente principale (par exemple, le chargement de données à partir du réseau), mais plutôt de les effectuer sur les autres files d'attente pour maintenir l'interface utilisateur dégelée. et sensible aux actions de l'utilisateur. Si nous laissons l’interface utilisateur modifiée sur les autres files d’attente, les modifications peuvent être effectuées selon un calendrier et une vitesse différents et inattendus. Certains éléments de l'interface utilisateur peuvent être dessinés avant ou après leur utilisation. Il peut planter l'interface utilisateur. Nous devons également garder à l'esprit que, puisque les files d'attente globales sont files d'attente système, le système peut exécuter d'autres tâches.
Qualité de service/priorité .
Les files d'attente ont également différentes qos (qualité de service) , ce qui permet à la tâche d'exécuter une priorité (du plus haut au plus bas ici):
. userInteractive - file d'attente principale
. userInitiated - pour les tâches lancées par l'utilisateur sur lesquelles l'utilisateur attend une réponse.
.util - pour les tâches qui prennent un certain temps et ne nécessitent pas de réponse immédiate, par exemple, le travail avec des données
. background - pour les tâches qui ne sont pas liées à la partie visuelle et qui ne sont pas strictes pour l'heure d'exécution.
Il y a aussi
. file d'attente qui ne transfère pas les informations qos. S'il n'a pas été possible de détecter le qos le qos sera utilisé entre . UserInitiated et . Utility.
Les tâches peuvent être effectuées de manière synchrone ou de manière asynchrone .
Synchronous La fonction ne restitue le contrôle à la file d'attente actuelle qu'une fois la tâche terminée. Il bloque la file d'attente et attend que la tâche soit terminée.
Asynchrone La fonction renvoie le contrôle à la file d'attente actuelle juste après l'envoi de la tâche à exécuter sur la file d'attente différente. Il n'attend pas que la tâche soit terminée. Cela ne bloque pas la file d'attente.
Problèmes courants.
Les erreurs les plus courantes commises par les programmeurs lors de la projection d'applications concurrentes sont les suivantes:
NE JAMAIS appeler la fonction de synchronisation sur la file d'attente principale .
Si vous appelez la fonction de synchronisation sur la file d'attente principale, celle-ci sera bloquée et la file d'attente attendra que la tâche soit terminée, mais la tâche ne sera jamais terminée, car elle ne pourra même pas démarrer. en raison de la file d'attente est déjà bloqué. Cela s'appelle une impasse .
Quand utiliser la synchronisation? Quand nous devons attendre que la tâche soit terminée. F.e. quand on s'assure qu'une fonction/méthode n'est pas appelée en double. F.e. nous avons la synchronisation et essayons d'empêcher que ce soit un double appel jusqu'à ce qu'il soit complètement terminé. Voici un code pour cette préoccupation:
Comment savoir ce qui a provoqué le rapport d'erreur sur un périphérique IOS??
Lorsque vous utilisez async
, la file d’appel est poursuivie sans attendre que le bloc distribué soit exécuté. Au contraire, sync
fera que la file d’appel s’arrête et attend que le travail que vous avez réparti dans le bloc soit terminé. Par conséquent, sync
est susceptible de conduire à des blocages. Essayez d’exécuter DispatchQueue.main.sync
depuis la file principale et l’application sera gelée, car la file d’appel attendra jusqu’à ce que le bloc distribué soit terminé, mais elle ne pourra même pas démarrer (car la file est arrêtée et en attente).
Quand utiliser sync
? Lorsque vous devez attendre que quelque chose soit fait sur une file d'attente DIFFERENT et continuer à travailler uniquement sur votre file d'attente actuelle
Exemple d'utilisation de la synchronisation:
Sur une file d'attente série, vous pouvez utiliser sync
en tant que mutex afin de vous assurer qu'un seul thread est capable d'exécuter le morceau de code protégé en même temps.