web-dev-qa-db-fra.com

Comment faire du multithreading, de la concurrence ou du parallélisme dans iOS Swift?

Existe-t-il un moyen de créer un thread de travail dans Swift?, Par exemple, s'il existe une fonctionnalité majeure qui nécessite beaucoup de calculs et entraîne donc le retard du thread principal pendant quelques secondes, si je souhaite déplacer cette fonctionnalité vers un thread séparé ou un thread qui ne bloque pas le thread principal est-il possible de le faire avec Swift?

J'ai parcouru les composants de base et avancés de la Apple Documentation pour Swift mais il n'y a rien sur la concurrence ou le parallélisme, quelqu'un sait-il comment faire (si possible)?

36
Martin Cazares

Vous pouvez également utiliser des files d'attente d'opérations. Dans Swift 3:

let queue = OperationQueue()

queue.addOperation() {
    // do something in the background

    OperationQueue.main.addOperation() {
        // when done, update your UI and/or model on the main queue
    }
}

Soit cela, soit GCD, qui Andy illustré , fonctionne très bien.

Voir Guide de programmation d'accès concurrentiel d'Apple pour les avantages relatifs des files d'attente d'opérations et des files d'attente de répartition (alias Grand Central Dispatch, GCD). Bien que ce guide illustre encore les exemples utilisant Objective-C, l'API et les concepts sont fondamentalement les mêmes dans Swift (utilisez simplement la syntaxe Swift)). la documentation pour GCD et les files d'attente d'opérations dans Xcode décrit à la fois Objective-C et Swift APIs.


Soit dit en passant, vous remarquerez que dans l'exemple ci-dessus ainsi que dans la démonstration GCD d'Andy, nous avons utilisé des "fermetures de fin". Par exemple, si vous regardez la définition addOperationWithBlock, qui est définie comme une fonction avec un paramètre qui est une "fermeture" (qui est analogue à un bloc dans Objective-C):

func addOperation(_ block: @escaping () -> Swift.Void)

Cela pourrait vous amener à supposer que vous l'invoqueriez comme suit:

queue.addOperation({
    // do something in the background
})

Mais lorsque le dernier paramètre d'une fonction est une fermeture, la syntaxe de fermeture finale vous permet de retirer ce paramètre de fermeture final des parenthèses de la fonction et de le déplacer après la fonction, ce qui donne:

queue.addOperation() {
    // do something in the background
}

Et comme il ne reste plus rien entre parenthèses, vous pouvez même aller plus loin et supprimer ces parenthèses vides:

queue.addOperation {
    // do something in the background
}

J'espère que cela illustre comment interpréter les déclarations de fonction NSOperationQueue/OperationQueue et/ou GCD et les utiliser dans votre code.

46
Rob

Vous pouvez utiliser Grand Central Dispatch (GCD) pour de telles tâches.

Ceci est un exemple de base:

let backgroundQueue: dispatch_queue_t = dispatch_queue_create("com.a.identifier", DISPATCH_QUEUE_CONCURRENT)

// can be called as often as needed
dispatch_async(backgroundQueue) {
    // do calculations
}

// release queue when you are done with all the work
dispatch_release(backgroundQueue)
17
Andy

Cette bibliothèque vous permet de décrire la concurrence d'une manière super expressive:

func handleError(_ error) { ... }

HoneyBee.start(on: DispatchQueue.main) { root in
    root.setErrorHandler(handleError)
        .chain(function1) // runs on main queue
        .setBlockPerformer(DispatchQueue.global())
        .chain(function2) // runs on background queue
        .branch { stem in
            stem.chain(func3) // runs in parallel with func4
            +
            stem.chain(func4) // runs in parallel with func3
        }
        .chain(func5) // runs after func3 and func4 have finished
        .setBlockPerformer(DispatchQueue.main)
        .chain(updateUIFunc)
}
0
Alex Lynch