web-dev-qa-db-ger.com

Wie verwende ich einen Hintergrund-Thread in Swift?

Wie verwendet man Threading in Swift?

dispatchOnMainThread:^{

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

}];
291
Anshul

Swift 3.0+

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")
    }
}

Swift 1.2 bis 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 - Bekanntes Problem

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

660
tobiasdm

Es wird empfohlen, eine wiederverwendbare Funktion zu definieren, auf die mehrmals zugegriffen werden kann.

WIEDERVERWENDBARE FUNKTION:

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

SAGE:

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
    })
118
Dale Clifford

Dan Beaulieus Antwort in Swift5 (funktioniert auch seit 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()
                })
            }
        }
    }

}

Verwendungszweck

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 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.

40
Said Sikira

Aus Jameson Quaves Tutorial

Swift 2

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

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)
    }
}
25
iOS

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
    }
}
22
phuongle

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)
     }
}
21

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:

  1. beforeTask:()->Void wird im UI-Thread unmittelbar vor Ausführung der Task aufgerufen.
  2. backgroundTask: (param:BGParam)->BGResult wird unmittelbar danach im Hintergrund-Thread aufgerufen
  3. afterTask:(param:BGResult)->Void wird im UI-Thread mit dem Ergebnis der Hintergrundaufgabe aufgerufen
9
Nikita Kurtin

Da 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

  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,3s/6,1s/4,0s/4,0s/3,8s

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.

6
Cosmin

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

2
Anil Dhameliya

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
}
1
Viral Savaliya

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()
            }
        }
    }
}
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