Comment créer une file d'attente de répartition dans Swift 3

403

Dans Swift 2, j'ai pu créer une file d'attente avec le code suivant:

let concurrentQueue = dispatch_queue_create("com.swift3.imageQueue", DISPATCH_QUEUE_CONCURRENT)

Mais cela ne se compile pas dans Swift 3.

Quelle est la meilleure façon d'écrire ceci dans Swift 3?

Karthik Kumar
la source
2
Duplicata possible
rickster
Swift 4 dispose de 3 paramètres supplémentaires pour créer une file d'attente série. Comment les utiliser pour créer une file d'attente série? DispatchQueue.init (label:, qos:, attributes:, autoreleaseFrequency:, target
:)
@ nr5 Les files d'attente sont en série par défaut, il suffit donc de les utiliser uniquement DispatchQueue(label: "your-label")pour une file d'attente en série. Les paramètres supplémentaires ont tous des valeurs par défaut.
jbg

Réponses:

1131

Création d'une file d'attente simultanée

let concurrentQueue = DispatchQueue(label: "queuename", attributes: .concurrent)
concurrentQueue.sync {

}  

Créer une file d'attente série

let serialQueue = DispatchQueue(label: "queuename")
serialQueue.sync { 

}

Obtenir la file d'attente principale de manière asynchrone

DispatchQueue.main.async {

}

Obtenir la file d'attente principale de manière synchrone

DispatchQueue.main.sync {

}

Pour obtenir l'un des fils d'arrière-plan

DispatchQueue.global(qos: .background).async {

}

Xcode 8.2 beta 2:

Pour obtenir l'un des fils d'arrière-plan

DispatchQueue.global(qos: .default).async {

}

DispatchQueue.global().async {
    // qos' default value is ´DispatchQoS.QoSClass.default`
}

Si vous souhaitez en savoir plus sur l'utilisation de ces files d'attente .Voir cette réponse

Ce gars iOS paresseux 웃
la source
3
Vous pouvez réellement omettre attributes: .seriallors de la création d' une file d' attente de série: let serialQueue = DispatchQueue(label: "queuename").
kean
15
Dans Xcode 8 beta 4, il n'y a pas d'option .serial, vous devez donc créer une file d'attente série en omettant le .concurrent dans les attributs.
Oleg Sherman
J'ai besoin d'accéder à DispatchQueue de Swift3 dans objc mais j'ai obtenu l'erreur suivante Impossible d'initialiser une variable de type '__strong dispatch_queue_t' (alias 'NSObject <OS_dispatch_queue> * __ strong') avec une valeur de type 'OS_dispatch_queue * _Nonnull' lors de la répartition de backgroundQueue_t = [File d'attente SwiftClass]; qui est une variable statique de DispatchQueue dans swift
ideerge
DispatchQueue.main.asynchronously (DispatchQueue.main) {self.mapView.add (self.mapPolyline)} dans Swift 3.0, j'ai essayé avec DispatchQueue.global (). Asynchronously (DispatchQueue.main) {self.mapView.add (self .mapPolyline)} mais les deux affichent la même erreur que "la valeur de type dispathQuoue n'a pas de membre de manière asynchrone"
Abirami Bala
1
à partir du code de l'OP, pourquoi Apple se concentre-t-il sur l'utilisation de "com.swift3.imageQueue" . Je vois que l'étiquette comporte 3 parties. Pourquoi donc? que représente chaque pièce? Je ne reçois pas le formatage
Honey
55

Compile sous> = Swift 3 . Cet exemple contient la plupart de la syntaxe dont nous avons besoin.

QoS - nouvelle syntaxe de qualité de service

weak self - perturber les cycles de rétention

si l'individu n'est pas disponible, ne rien faire

async global utility queue- pour la requête réseau, n'attend pas le résultat, c'est une file d'attente simultanée, le bloc (généralement) n'attend pas au démarrage. L'exception pour une file d'attente simultanée peut être, lorsque sa limite de tâches a été précédemment atteinte, puis la file d'attente se transforme temporairement en file d'attente série et attend jusqu'à ce qu'une tâche précédente dans cette file d'attente se termine.

async main queue- pour toucher l'interface utilisateur, le bloc n'attend pas le résultat, mais attend son emplacement au départ. La file d'attente principale est une file d'attente série.

Bien sûr, vous devez ajouter une vérification d'erreur à cela ...

DispatchQueue.global(qos: .utility).async { [weak self] () -> Void in

    guard let strongSelf = self else { return }

    strongSelf.flickrPhoto.loadLargeImage { loadedFlickrPhoto, error in

        if error != nil {
            print("error:\(error)")
        } else {
            DispatchQueue.main.async { () -> Void in
                activityIndicator.removeFromSuperview()
                strongSelf.imageView.image = strongSelf.flickrPhoto.largeImage
            }
        }
    }
}
t1ser
la source
6
Lors du codage dans Swift 3, habituez-vous à condenser et à supprimer 30% de votre code précédent :-)
t1ser
Merci pour l'exemple de [moi faible]!
imike
1
Il est préférable de guardqui selfne sont pas nilen haut, de sorte qu'aucun du code est exécuté si elle est nil, par exemple, guard strongSelf = self else { return }.
Scott Gardner
@ t1 Pourriez-vous me dire où trouver la documentation pour GCD écrite avec du code dans Swift 3? Je n'ai trouvé celui écrit en Objective C . Quelqu'un ici me pointait vers une vidéo de la WWDC, mais je veux lire la documentation officielle avec des exemples dans Swift 3 et il n'y a aucun moyen de la trouver.
bibscy
1
Ne pas utiliser .global(qos: .background)pour IO (requête réseau). Utilisez .global(qos: .default)ou à la .global(qos: .utility)place.
Pedro Paulo Amorim
28

Compilé dans XCode 8, Swift 3 https://github.com/rpthomas/Jedisware

 @IBAction func tap(_ sender: AnyObject) {

    let thisEmail = "emailaddress.com"
    let thisPassword = "myPassword" 

    DispatchQueue.global(qos: .background).async {

        // Validate user input

        let result = self.validate(thisEmail, password: thisPassword)

        // Go back to the main thread to update the UI
        DispatchQueue.main.async {
            if !result
            {
                self.displayFailureAlert()
            }

        }
    }

}
R Thomas
la source
12

Puisque la question OP a déjà été répondue ci-dessus, je veux juste ajouter quelques considérations de vitesse:

Cela fait beaucoup de différence quelle classe de priorité vous affectez à votre fonction asynchrone dans DispatchQueue.global .

Je ne recommande pas d'exécuter des tâches avec la priorité de thread .background, en particulier sur l'iPhone X où la tâche semble être allouée sur les cœurs de faible puissance.

Voici quelques données réelles d'une fonction de calcul intensif qui lit à partir d'un fichier XML (avec mise en mémoire tampon) et effectue une interpolation des données:

Nom du périphérique / .background / .utility / .default / .userInitiated / .userInteractive

  1. iPhone X: 18,7 s / 6,3 s / 1,8 s / 1,8 s / 1,8 s
  2. iPhone 7: 4,6 s / 3,1 s / 3,0 s / 2,8 s / 2,6 s
  3. iPhone 5s: 7,3 s / 6,1 s / 4,0 s / 4,0 s / 3,8 s

Notez que l'ensemble de données n'est pas le même pour tous les appareils. C'est le plus grand sur l'iPhone X et le plus petit sur l'iPhone 5s.

Cosmin
la source
1
Grande info.
M'a
1
@Myk Si l'utilisateur a lancé et / ou attend les résultats, vous devez utiliser .userInitiated ou .userInteractive pour que toute autre opération soit inversée. Dans la plupart des autres cas, .default serait un bon choix.
Cosmin
6

J'ai fait cela et cela est particulièrement important si vous souhaitez actualiser votre interface utilisateur pour afficher de nouvelles données sans que l'utilisateur ne s'en rende compte comme dans UITableView ou UIPickerView.

    DispatchQueue.main.async
 {
   /*Write your thread code here*/
 }
Asfand Shabbir
la source
3
 DispatchQueue.main.async {
          self.collectionView?.reloadData() // Depends if you were populating a collection view or table view
    }


OperationQueue.main.addOperation {
    self.lblGenre.text = self.movGenre
}

// utilisez Operation Queue si vous devez remplir les objets (labels, imageview, textview) sur votre viewcontroller

Fritz Gerald Moran
la source
2
   let concurrentQueue = dispatch_queue_create("com.swift3.imageQueue", DISPATCH_QUEUE_CONCURRENT) //Swift 2 version

   let concurrentQueue = DispatchQueue(label:"com.swift3.imageQueue", attributes: .concurrent) //Swift 3 version

J'ai retravaillé votre code dans Xcode 8, Swift 3 et les changements sont marqués contrairement à votre version Swift 2.

gosborne3
la source
Cela semble plus propre que ce que j'ai écrit. Merci.
gosborne3
2

Swift 3

vous voulez appeler une fermeture en code rapide puis vous voulez changer dans le storyboard ya tout type de changement appartient pour voir votre application va planter

mais vous souhaitez utiliser la méthode de répartition, votre application ne se bloquera pas

méthode asynchrone

DispatchQueue.main.async 
{
 //Write code here                                   

}

méthode de synchronisation

DispatchQueue.main.sync 
{
     //Write code here                                  

}
Amul4608
la source
Je veux utiliser la méthode asynchrone dans le temps d'appel de service, mon code est DispatchQueue.main.async {let objstory1 = self.storyboard? .InstantiateViewController (withIdentifier: "HomeViewController") as! HomeViewController _ = self.navigationController? .PushViewController (objstory1, animé: false)}
Amul4608
1
Ne jamais utiliserDispatchQueue.main.sync
trickster77777
Les appels de synchronisation sur la file d'attente principale causeront certainement des problèmes.
Tofu Warrior
2
DispatchQueue.main.async(execute: {

// write code

})

File d'attente série:

let serial = DispatchQueue(label: "Queuename")

serial.sync { 

 //Code Here

}

File d'attente simultanée:

 let concurrent = DispatchQueue(label: "Queuename", attributes: .concurrent)

concurrent.sync {

 //Code Here
}
Hitesh Chauhan
la source
Cela ne crée pas de file d'attente de répartition, il vous place simplement dans la file d'attente principale après un passage dans la boucle d'exécution.
buildsucceeded
1

Pour Swift 3

   DispatchQueue.main.async {
        // Write your code here
    }
Joseph Mikko Manoza
la source
@Moritz Je ne pourrais pas être plus d'accord, malheureusement.
Orkhan Alikhanov
1
 let newQueue = DispatchQueue(label: "newname")
 newQueue.sync { 

 // your code

 }
Profond
la source
1

Mise à jour pour Swift 5

File d'attente série

let serialQueue = DispatchQueue.init(label: "serialQueue")
serialQueue.async {
    // code to execute
}

File d'attente simultanée

let concurrentQueue = DispatchQueue.init(label: "concurrentQueue", qos: .background, attributes: .concurrent, autoreleaseFrequency: .inherit, target: nil)

concurrentQueue.async {
// code to execute
}

De la documentation Apple :

Paramètres

étiquette

Une étiquette de chaîne à attacher à la file d'attente pour l'identifier de manière unique dans les outils de débogage tels que les instruments, les échantillons, les photos de pile et les rapports de plantage. Étant donné que les applications, les bibliothèques et les frameworks peuvent tous créer leurs propres files d'attente de répartition, un style de dénomination DNS inversé (com.example.myqueue) est recommandé. Ce paramètre est facultatif et peut être NULL.

qos

Niveau de qualité de service à associer à la file d'attente. Cette valeur détermine la priorité à laquelle le système planifie les tâches à exécuter. Pour une liste des valeurs possibles, voir DispatchQoS.QoSClass.

les attributs

Les attributs à associer à la file d'attente. Incluez l'attribut concurrent pour créer une file d'attente de répartition qui exécute les tâches simultanément. Si vous omettez cet attribut, la file d'attente de répartition exécute les tâches en série.

autoreleaseFrequency

Fréquence de libération automatique des objets créés par les blocs que la file d'attente planifie. Pour une liste des valeurs possibles, voir DispatchQueue.AutoreleaseFrequency .

cible

La file d'attente cible sur laquelle exécuter les blocs. Spécifiez DISPATCH_TARGET_QUEUE_DEFAULT si vous souhaitez que le système fournisse une file d'attente appropriée pour l'objet actuel.

Mithra Singam
la source
-3

c'est maintenant simplement:

let serialQueue = DispatchQueue(label: "my serial queue")

la valeur par défaut est série, pour obtenir simultanément, vous utilisez l'argument facultatif des attributs .concurrent

tylernol
la source
Vous feriez mieux de mettre à jour votre réponse en ajoutant seiralQueue.async {}. @tylemol
DawnSong
-3
DispatchQueue.main.async(execute: {
   // code
})
Hitesh Chauhan
la source
Merci pour cet extrait de code, qui peut fournir une aide immédiate. Une explication appropriée améliorerait considérablement sa valeur éducative en montrant pourquoi il s'agit d'une bonne solution au problème, et la rendrait plus utile aux futurs lecteurs ayant des questions similaires, mais pas identiques. Veuillez modifier votre réponse pour ajouter des explications et donner une indication des limitations et hypothèses applicables.
Toby Speight
-4

Vous pouvez créer une file d'attente de répartition à l'aide de ce code dans swift 3.0

DispatchQueue.main.async
 {
   /*Write your code here*/
 }

   /* or */

let delayTime = DispatchTime.now() + Double(Int64(0.5 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)                   
DispatchQueue.main.asyncAfter(deadline: delayTime)
{
  /*Write your code here*/
}
Nand Parikh
la source
1
Désolé, cela ne crée pas de file d'attente de répartition, c'est l'accès à la file d'attente principale après un passage dans la boucle d'exécution.
buildsucceeded