web-dev-qa-db-fra.com

Comment utiliser le fil de fond dans swift?

Comment utiliser le threading en quick?

dispatchOnMainThread:^{

    NSLog(@"Block Executed On %s", dispatch_queue_get_label(dispatch_get_current_queue()));

}];
291
Anshul

Swift 3.0+

Beaucoup a été modernisé dans Swift 3.0. Exécuter quelque chose sur le fil de fond ressemble à ceci:

DispatchQueue.global(qos: .background).async {
    print("This is run on the background queue")

    DispatchQueue.main.async {
        print("This is run on the main queue, after the previous code in outer block")
    }
}

Swift 1.2 à 2.3

let qualityOfServiceClass = QOS_CLASS_BACKGROUND
let backgroundQueue = dispatch_get_global_queue(qualityOfServiceClass, 0)
dispatch_async(backgroundQueue, {
    print("This is run on the background queue")

    dispatch_async(dispatch_get_main_queue(), { () -> Void in
        print("This is run on the main queue, after the previous code in outer block")
    })
})

Pre Swift 1.2 - Problème connu

À partir de Swift 1.1 Apple ne supportait pas la syntaxe ci-dessus sans quelques modifications. Passer QOS_CLASS_BACKGROUND ne fonctionnait pas, utilisez plutôt Int(QOS_CLASS_BACKGROUND.value).

Pour plus d'informations, voir Documentation d'Apple

660
tobiasdm

La meilleure pratique consiste à définir une fonction réutilisable accessible plusieurs fois.

FONCTION RÉUTILISABLE:

par exemple. quelque part comme AppDelegate.Swift en tant que fonction globale.

func backgroundThread(_ delay: Double = 0.0, background: (() -> Void)? = nil, completion: (() -> Void)? = nil) {
    dispatch_async(dispatch_get_global_queue(Int(QOS_CLASS_USER_INITIATED.value), 0)) {
        background?()

        let popTime = dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC)))
        dispatch_after(popTime, dispatch_get_main_queue()) {
            completion?()
        }
    }
}

Remarque: dans Swift 2.0, remplacez QOS_CLASS_USER_INITIATED.value ci-dessus par QOS_CLASS_USER_INITIATED.rawValue à la place

SAGE:

A. Pour exécuter un processus en arrière-plan avec un délai de 3 secondes:

    backgroundThread(3.0, background: {
            // Your background function here
    })

B. Pour exécuter un processus en arrière-plan, exécutez une complétion au premier plan:

    backgroundThread(background: {
            // Your function here to run in the background
    },
    completion: {
            // A function to run in the foreground when the background thread is complete
    })

C. Pour retarder de 3 secondes - notez l’utilisation du paramètre de complétion sans paramètre de fond:

    backgroundThread(3.0, completion: {
            // Your delayed function here to be run in the foreground
    })
118
Dale Clifford

La réponse de Dan Beaulieu dans Swift5 (fonctionne également depuis Swift 3.0.1).

Swift 5.0.1

extension DispatchQueue {

    static func background(delay: Double = 0.0, background: (()->Void)? = nil, completion: (() -> Void)? = nil) {
        DispatchQueue.global(qos: .background).async {
            background?()
            if let completion = completion {
                DispatchQueue.main.asyncAfter(deadline: .now() + delay, execute: {
                    completion()
                })
            }
        }
    }

}

Usage

DispatchQueue.background(delay: 3.0, background: {
    // do something in background
}, completion: {
    // when background job finishes, wait 3 seconds and do something in main thread
})

DispatchQueue.background(background: {
    // do something in background
}, completion:{
    // when background job finished, do something in main thread
})

DispatchQueue.background(delay: 3.0, completion:{
    // do something in main thread after 3 seconds
})
68
frouo

Swift 3 version

Swift 3 utilise la nouvelle classe DispatchQueue pour gérer les files d'attente et les threads. Pour exécuter quelque chose sur le fil d’arrière-plan que vous utiliseriez:

let backgroundQueue = DispatchQueue(label: "com.app.queue", qos: .background)
backgroundQueue.async {
    print("Run on background thread")
}

Ou si vous voulez quelque chose en deux lignes de code:

DispatchQueue.global(qos: .background).async {
    print("Run on background thread")

    DispatchQueue.main.async {
        print("We finished that.")
        // only back on the main thread, may you access UI:
        label.text = "Done."
    }
}

Vous pouvez également obtenir des informations détaillées sur GDC dans Swift 3 in ce tutoriel .

40
Said Sikira

De le tutoriel de Jameson Quave

Swift 2

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
    //All stuff here
})
35
alex

Dans Swift 4.2 et Xcode 10.1

Nous avons trois types de files d'attente:

1. File d'attente principale: La file d'attente principale est une file d'attente série créée par le système et associée au thread principal de l'application.

2. File d'attente globale: La file d'attente globale est une file d'attente simultanée que nous pouvons demander en ce qui concerne la priorité des tâches.

3. Files d'attente personnalisées: peuvent être créées par l'utilisateur. Les files d'attente simultanées personnalisées sont toujours mappées dans l'une des files d'attente globales en spécifiant une propriété de qualité de service (QoS).

DispatchQueue.main//Main thread
DispatchQueue.global(qos: .userInitiated)// High Priority
DispatchQueue.global(qos: .userInteractive)//High Priority (Little Higher than userInitiated)
DispatchQueue.global(qos: .background)//Lowest Priority
DispatchQueue.global(qos: .default)//Normal Priority (after High but before Low)
DispatchQueue.global(qos: .utility)//Low Priority
DispatchQueue.global(qos: .unspecified)//Absence of Quality

Toutes ces files d'attente peuvent être exécutées de deux manières

1. Exécution synchrone

2. Exécution asynchrone

DispatchQueue.global(qos: .background).async {
    // do your job here
    DispatchQueue.main.async {
        // update ui here
    }
}

//Perform some task and update UI immediately.
DispatchQueue.global(qos: .userInitiated).async {  
    // Perform task
    DispatchQueue.main.async {  
        // Update UI
        self.tableView.reloadData()  
    }
}

//To call or execute function after some time
DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
    //Here call your function
}

//If you want to do changes in UI use this
DispatchQueue.main.async(execute: {
    //Update UI
    self.tableView.reloadData()
})

Depuis AppCoda: https://www.appcoda.com/grand-central-dispatch/

//This will print synchronously means, it will print 1-9 & 100-109
func simpleQueues() {
    let queue = DispatchQueue(label: "com.appcoda.myqueue")

    queue.sync {
        for i in 0..<10 {
            print("????", i)
        }
    }

    for i in 100..<110 {
        print("Ⓜ️", i)
    }
}

//This will print asynchronously 
func simpleQueues() {
    let queue = DispatchQueue(label: "com.appcoda.myqueue")

    queue.async {
        for i in 0..<10 {
            print("????", i)
        }
    }

    for i in 100..<110 {
        print("Ⓜ️", i)
    }
}
25
iOS

Vous devez séparer les modifications que vous souhaitez exécuter en arrière-plan des mises à jour que vous souhaitez exécuter sur l'interface utilisateur:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
    // do your task

    dispatch_async(dispatch_get_main_queue()) {
        // update some UI
    }
}
22
phuongle

Swift 4.x

Mettez ceci dans un fichier:

func background(work: @escaping () -> ()) {
    DispatchQueue.global(qos: .userInitiated).async {
        work()
    }
}

func main(work: @escaping () -> ()) {
    DispatchQueue.main.async {
        work()
    }
}

puis appelez-le où vous avez besoin:

background {
     //background job
     main {
       //update UI (or what you need to do in main thread)
     }
}
21

Quoi qu'il en soit, je souhaite partager ma solution orientée objet à jour pour Swift 5 .

s'il vous plaît vérifier: AsyncTask

Inspiré conceptuellement par AsyncTask d'Android, j'ai écrit ma propre classe dans Swift

AsyncTask permet d'utiliser correctement et facilement le fil de l'interface utilisateur. Cette classe permet d'effectuer des opérations en arrière-plan et de publier les résultats sur le thread d'interface utilisateur.

Voici quelques exemples d'utilisation

Exemple 1 -

AsyncTask(backgroundTask: {(p:String)->Void in//set BGParam to String and BGResult to Void
        print(p);//print the value in background thread
    }).execute("Hello async");//execute with value 'Hello async'

Exemple 2 -

let task2=AsyncTask(beforeTask: {
           print("pre execution");//print 'pre execution' before backgroundTask
        },backgroundTask:{(p:Int)->String in//set BGParam to Int & BGResult to String
            if p>0{//check if execution value is bigger than zero
               return "positive"//pass String "poitive" to afterTask
            }
            return "negative";//otherwise pass String "negative"
        }, afterTask: {(p:String) in
            print(p);//print background task result
    });
    task2.execute(1);//execute with value 1

Il a 2 types génériques:

  • BGParam - le type du paramètre envoyé à la tâche lors de son exécution.
  • BGResult - le type du résultat du calcul en arrière-plan.

    Lorsque vous créez une AsyncTask, vous pouvez affecter ces types à tout ce dont vous avez besoin pour entrer et sortir de la tâche en arrière-plan, mais si vous n'avez pas besoin de ces types, vous pouvez le marquer comme inutilisé en le définissant simplement comme suit: Void ou avec une syntaxe plus courte: ()

Lorsqu'une tâche asynchrone est exécutée, elle passe par 3 étapes:

  1. beforeTask:()->Void invoqué sur le thread d'interface utilisateur juste avant l'exécution de la tâche.
  2. backgroundTask: (param:BGParam)->BGResult invoqué sur le thread d'arrière-plan immédiatement après
  3. afterTask:(param:BGResult)->Void invoqué sur le thread d'interface utilisateur avec le résultat de la tâche en arrière-plan
9
Nikita Kurtin

Étant donné que la question relative à l'OP a déjà été répondue ci-dessus, je souhaite simplement ajouter quelques considérations de rapidité:

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

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

Nom du périphérique/. Fond/.util/. Défaut/. UserInitiated/. UserInteractive

  1. iPhone X: 18,7s/6,3s/1,8s/1,8s/1,8s
  2. iPhone 7: 4.6s/3.1s/3.0s/2.8s/2.6s
  3. iPhone 5s: 7.3s/6.1s/4.0s/4.0s/3.8s

Notez que le jeu 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 5.

6
Cosmin

Grand Central Dispatch est utilisé pour gérer le multitâche dans nos applications iOS.

Vous pouvez utiliser ce code

// Using time interval

DispatchQueue.main.asyncAfter(deadline: DispatchTime.now()+1) {
    print("Hello World")
}

// Background thread
queue.sync {
     for i in 0..<10 {
          print("Hello", i)
     }
}

// Main thread
for i in 20..<30 {
     print("Hello", i)
}

Plus d'informations utilisez ce lien: https://www.programminghub.us/2018/07/integrate-dispatcher-in-Swift.html

2
Anil Dhameliya

Fonction polyvalente pour fil

public enum QueueType {
        case Main
        case Background
        case LowPriority
        case HighPriority

        var queue: DispatchQueue {
            switch self {
            case .Main:
                return DispatchQueue.main
            case .Background:
                return DispatchQueue(label: "com.app.queue",
                                     qos: .background,
                                     target: nil)
            case .LowPriority:
                return DispatchQueue.global(qos: .userInitiated)
            case .HighPriority:
                return DispatchQueue.global(qos: .userInitiated)
            }
        }
    }

    func performOn(_ queueType: QueueType, closure: @escaping () -> Void) {
        queueType.queue.async(execute: closure)
    }

Utilisez-le comme:

performOn(.Background) {
    //Code
}
1
Viral Savaliya

J'aime beaucoup la réponse de Dan Beaulieu, mais elle ne fonctionne pas avec Swift 2.2 et je pense que nous pouvons éviter ces vilains déroulements forcés!

func backgroundThread(delay: Double = 0.0, background: (() -> Void)? = nil, completion: (() -> Void)? = nil) {

    dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0)) {

        background?()

        if let completion = completion{
            let popTime = dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC)))
            dispatch_after(popTime, dispatch_get_main_queue()) {
                completion()
            }
        }
    }
}
1
rougeExciter
dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0), {
    // Conversion into base64 string
    self.uploadImageString =  uploadPhotoDataJPEG.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.EncodingEndLineWithCarriageReturn)
})
0
A.G