Wie verwendet man Threading in Swift?
dispatchOnMainThread:^{
NSLog(@"Block Executed On %s", dispatch_queue_get_label(dispatch_get_current_queue()));
}];
Vieles wurde modernisiert in Swift 3.0. Das Ausführen von etwas im Hintergrund-Thread sieht folgendermaßen aus:
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")
}
}
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")
})
})
Ab Swift 1.1 Apple hat die obige Syntax ohne einige Änderungen nicht unterstützt. Das Übergeben von QOS_CLASS_BACKGROUND
hat nicht wirklich funktioniert, verwenden Sie stattdessen Int(QOS_CLASS_BACKGROUND.value)
.
Weitere Informationen finden Sie unter Dokumentation zu Äpfeln
Es wird empfohlen, eine wiederverwendbare Funktion zu definieren, auf die mehrmals zugegriffen werden kann.
z.B. irgendwo wie AppDelegate.Swift als globale Funktion.
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?()
}
}
}
Hinweis: Ersetzen Sie in Swift 2.0 stattdessen QOS_CLASS_USER_INITIATED.value durch QOS_CLASS_USER_INITIATED.rawValue
A. So führen Sie einen Prozess mit einer Verzögerung von 3 Sekunden im Hintergrund aus:
backgroundThread(3.0, background: {
// Your background function here
})
B. Um einen Prozess im Hintergrund auszuführen, führen Sie eine Vervollständigung im Vordergrund aus:
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. Um 3 Sekunden zu verzögern - beachten Sie die Verwendung des Beendigungsparameters ohne Hintergrundparameter:
backgroundThread(3.0, completion: {
// Your delayed function here to be run in the foreground
})
Dan Beaulieus Antwort in Swift5 (funktioniert auch seit Swift 3.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()
})
}
}
}
}
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
})
Swift 3 verwendet die neue Klasse DispatchQueue
, um Warteschlangen und Threads zu verwalten. Um etwas im Hintergrund-Thread auszuführen, würden Sie Folgendes verwenden:
let backgroundQueue = DispatchQueue(label: "com.app.queue", qos: .background)
backgroundQueue.async {
print("Run on background thread")
}
Oder wenn Sie etwas in zwei Codezeilen wollen:
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."
}
}
Sie können in Swift 3 in dieses Tutorial auch einige ausführliche Informationen über GDC erhalten.
Swift 2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
//All stuff here
})
In Swift 4.2 und Xcode 10.1
Wir haben drei Arten von Warteschlangen:
1. Hauptwarteschlange: Die Hauptwarteschlange ist eine serielle Warteschlange, die vom System erstellt und dem Hauptthread der Anwendung zugeordnet wird.
2. Globale Warteschlange: Die globale Warteschlange ist eine gleichzeitige Warteschlange, die wir in Bezug auf die Priorität der Aufgaben anfordern können.
3. Benutzerdefinierte Warteschlangen: können vom Benutzer erstellt werden. Benutzerdefinierte gleichzeitige Warteschlangen werden immer einer der globalen Warteschlangen zugeordnet, indem eine Quality of Service-Eigenschaft (QoS) angegeben wird.
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
Diese Warteschlangen können auf zwei Arten ausgeführt werden
1. Synchrone Ausführung
2. Asynchrone Ausführung
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()
})
Von 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)
}
}
Sie müssen die Änderungen, die Sie im Hintergrund ausführen möchten, von den Updates trennen, die Sie auf der Benutzeroberfläche ausführen möchten:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
// do your task
dispatch_async(dispatch_get_main_queue()) {
// update some UI
}
}
Swift 4.x
Fügen Sie dies in eine Datei ein:
func background(work: @escaping () -> ()) {
DispatchQueue.global(qos: .userInitiated).async {
work()
}
}
func main(work: @escaping () -> ()) {
DispatchQueue.main.async {
work()
}
}
und nennen Sie es dann, wo Sie brauchen:
background {
//background job
main {
//update UI (or what you need to do in main thread)
}
}
Gute Antworten, trotzdem möchte ich meine objektorientierte Lösung teilen Aktuell für Swift 5 .
bitte probiere es aus: AsyncTask
Ich habe mich konzeptionell von Android's AsyncTask inspirieren lassen und meine eigene Klasse in Swift geschrieben
AsyncTask ermöglicht die ordnungsgemäße und einfache Verwendung des UI-Threads. Diese Klasse ermöglicht das Ausführen von Hintergrundoperationen und das Veröffentlichen von Ergebnissen im UI-Thread.
Hier sind einige Anwendungsbeispiele
Beispiel 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'
Beispiel 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
Es gibt zwei generische Typen:
BGParam
- Der Typ des Parameters, der bei der Ausführung an die Task gesendet wird.BGResult
- Der Typ des Ergebnisses der Hintergrundberechnung.
Wenn Sie eine AsyncTask erstellen, können Sie diese Typen an alles übergeben, was Sie für die Hintergrundaufgabe benötigen. Wenn Sie diese Typen jedoch nicht benötigen, können Sie sie als nicht verwendet markieren, indem Sie sie auf Folgendes festlegen: Void
oder mit kürzerer Syntax: ()
Wenn eine asynchrone Aufgabe ausgeführt wird, werden drei Schritte ausgeführt:
beforeTask:()->Void
wird im UI-Thread unmittelbar vor Ausführung der Task aufgerufen.backgroundTask: (param:BGParam)->BGResult
wird unmittelbar danach im Hintergrund-Thread aufgerufenafterTask:(param:BGResult)->Void
wird im UI-Thread mit dem Ergebnis der Hintergrundaufgabe aufgerufenDa die OP-Frage oben bereits beantwortet wurde, möchte ich nur einige Überlegungen zur Geschwindigkeit anstellen:
Ich empfehle nicht, Aufgaben mit der Thread-Priorität . Background auszuführen, insbesondere auf dem iPhone X, bei dem die Aufgabe anscheinend auf den Kernen mit geringem Stromverbrauch zugewiesen ist.
Hier sind einige reale Daten aus einer rechenintensiven Funktion, die aus einer XML-Datei (mit Pufferung) liest und Dateninterpolation durchführt:
Gerätename/. Hintergrund/. Dienstprogramm/. Standard/. UserInitiated/. UserInteractive
Beachten Sie, dass der Datensatz nicht für alle Geräte gleich ist. Es ist das größte auf dem iPhone X und das kleinste auf dem iPhone 5s.
Grand Central Dispatch wird für das Multitasking in unseren iOS-Apps verwendet.
Sie können diesen Code verwenden
// 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)
}
Weitere Informationen erhalten Sie über diesen Link: https://www.programminghub.us/2018/07/integrate-dispatcher-in-Swift.html
Mehrzweckfunktion für Thread
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)
}
Verwenden Sie es wie folgt:
performOn(.Background) {
//Code
}
Ich mag die Antwort von Dan Beaulieu wirklich, aber es funktioniert nicht mit Swift 2.2 und ich denke, wir können diese bösen, erzwungenen Auspackungen vermeiden!
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()
}
}
}
}
dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0), {
// Conversion into base64 string
self.uploadImageString = uploadPhotoDataJPEG.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.EncodingEndLineWithCarriageReturn)
})