如何使用后台线程在swift?

如何使用线程在迅速?

dispatchOnMainThread:^{


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


}];
357071 次浏览

Jameson Quave的教程

斯威夫特2

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

斯威夫特3.0 +

在Swift 3.0中有很多现代化。在后台队列上运行一些东西看起来像这样:

DispatchQueue.global(qos: .userInitiated).async {
print("This is run on a 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_USER_INITIATED
let backgroundQueue = dispatch_get_global_queue(qualityOfServiceClass, 0)
dispatch_async(backgroundQueue, {
print("This is run on a 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 -已知问题

从Swift 1.1开始,苹果在没有做一些修改的情况下不支持上述语法。传递QOS_CLASS_USER_INITIATED实际上不起作用,而是使用Int(QOS_CLASS_USER_INITIATED.value)

更多信息见苹果的文档

最佳实践是定义一个可多次访问的可重用函数。

可重用的功能:

例如,AppDelegate.swift是一个全局函数。

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

注意:在Swift 2.0中,将上面的QOS_CLASS_USER_INITIATED.value替换为QOS_CLASS_USER_INITIATED.rawValue

用法:

a .在后台运行一个进程,延迟3秒:

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

B.在后台运行一个进程,然后在前台运行一个补全:

    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.延迟3秒-注意使用completion参数而不使用background参数:

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

你必须将你想要在后台运行的更改与你想要在UI上运行的更新分开:

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


dispatch_async(dispatch_get_main_queue()) {
// update some UI
}
}
dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0), {
// Conversion into base64 string
self.uploadImageString =  uploadPhotoDataJPEG.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.EncodingEndLineWithCarriageReturn)
})

好答案,不管怎样,我想分享我的面向对象解决方案最新的swift 5

请查看它:AsyncTask

从概念上受到android的AsyncTask的启发,我用Swift写了自己的类

AsyncTask使UI线程能够正确和简单地使用。该类允许执行后台操作并在UI线程上发布结果。

下面是一些用法示例

例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'

例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

它有两个泛型类型:

  • BGParam -执行时发送给任务的参数类型。

  • BGResult -后台计算结果的类型。

    当你创建AsyncTask时,你可以将这些类型赋给你需要传入和传入后台任务的任何类型,但如果你不需要这些类型,你可以将其标记为未使用,只需将其设置为:Void或更短的语法:()

当一个异步任务执行时,它经过3个步骤:

  1. 在任务执行之前在UI线程上调用beforeTask:()->Void
  2. backgroundTask: (param:BGParam)->BGResult在后台线程调用后立即
  3. 在UI线程上调用后台任务的结果

我真的很喜欢Dan Beaulieu的答案,但是它在Swift 2.2中不起作用,我认为我们可以避免那些讨厌的强制打开!

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

Swift 3版本

Swift 3利用新的DispatchQueue类来管理队列和线程。要在后台线程上运行一些东西,你可以使用:

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

或者如果你想在两行代码中实现:

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

你也可以在本教程中获得一些关于Swift 3中GDC的深入信息。

Dan Beaulieu在swift5中给出了答案(从swift 3.0.1开始也可以工作)。

斯威夫特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()
})
}
}
}


}

使用

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

由于OP问题已经在上面得到了回答,我只想添加一些速度方面的考虑:

我不建议使用.background线程优先级运行任务,特别是在iPhone X上,因为任务似乎分配在低功耗内核上。

下面是一个计算密集型函数的一些真实数据,该函数从XML文件中读取(带缓冲)并执行数据插值:

设备名称/ .background / .utility / .default / .userInitiated / .userInteractive

  1. iPhone X: 18.7s / 6.3s / 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

注意,并不是所有设备的数据集都相同。iPhone X最大,iPhone 5s最小。

在我们的iOS应用中,中央调度是用来处理多任务的。

您可以使用此代码

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

更多信息请使用此链接:https://www.programminghub.us/2018/07/integrate-dispatcher-in-swift.html

在Swift 4.2和Xcode 10.1中

我们有三种类型的队列:

<强> 1。主要队列: 主队列是一个串行队列,由系统创建并与应用程序主线程相关联

<强> 2。全局队列: 全局队列是一个并发队列,我们可以根据任务的优先级请求它

3.自定义队列:可以由用户创建。通过指定服务质量属性(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

所有这些队列都可以以两种方式执行

1. 同步执行

2. 异步执行

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

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

快4.倍

把这些放到文件中:

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


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

然后在需要的地方调用它:

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

在Swift 4.2中,这是可行的。

import Foundation


class myThread: Thread
{
override func main() {
while(true) {
print("Running in the Thread");
Thread.sleep(forTimeInterval: 4);
}
}
}


let t = myThread();
t.start();


while(true) {
print("Main Loop");
sleep(5);
}

多用途螺纹功能

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

像这样使用它:

performOn(.Background) {
//Code
}

斯威夫特5

为了简化,创建一个“DispatchQueue+Extensions.swift”文件,内容如下:

import Foundation


typealias Dispatch = DispatchQueue


extension Dispatch {


static func background(_ task: @escaping () -> ()) {
Dispatch.global(qos: .background).async {
task()
}
}


static func main(_ task: @escaping () -> ()) {
Dispatch.main.async {
task()
}
}
}

用法:

Dispatch.background {
// do stuff


Dispatch.main {
// update UI
}
}

下面的代码是否有缺点(当需要启动前台屏幕之后)?

import Foundation
import UIKit


class TestTimeDelay {


static var connected:Bool = false
    

static var counter:Int = 0


static func showAfterDelayControl(uiViewController:UIViewController) {
NSLog("TestTimeDelay", "showAfterDelayControl")
}
    

static func tryReconnect() -> Bool {
counter += 1
NSLog("TestTimeDelay", "Counter:\(counter)")
return counter > 4
}


static func waitOnConnectWithDelay(milliseconds:Int, uiViewController: UIViewController) {
        

DispatchQueue.global(qos: .background).async {
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + DispatchTimeInterval.milliseconds(milliseconds), execute: {
waitOnConnect(uiViewController: uiViewController)
})
}
}


static func waitOnConnect(uiViewController:UIViewController) {


connected = tryReconnect()
if connected {
showAfterDelayControl(uiViewController: uiViewController)
}
else {
waitOnConnectWithDelay(milliseconds: 200, uiViewController:uiViewController)
}
}
}