如何在swift中使用后台线程?

时间:2014-06-05 09:16:45

标签: ios swift multithreading dispatch-queue

如何在swift中使用线程?

dispatchOnMainThread:^{

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

}];

16 个答案:

答案 0 :(得分:643)

Swift 3.0 +

Swift 3.0中有很多modernized。在后台线程上运行一些东西看起来像这样:

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 - 已知问题

从Swift 1.1开始,如果没有一些修改,Apple不支持上述语法。传递QOS_CLASS_BACKGROUND实际上并不起作用,而是使用Int(QOS_CLASS_BACKGROUND.value)

有关详细信息,请参阅Apples documentation

答案 1 :(得分:115)

最佳做法是定义可以多次访问的可重用函数。

可重复使用的功能:

e.g。像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 而不是

USAGE:

一个。要在后台运行一个延迟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
    })

℃。延迟3秒 - 注意使用没有背景参数的完成参数:

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

答案 2 :(得分:48)

Dan Beaulieu在swift5中的回答(自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()
                })
            }
        }
    }

}

用法

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

答案 3 :(得分:40)

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

您还可以在this tutorial中的Swift 3中获得有关GDC的一些深入信息。

答案 4 :(得分:34)

来自Jameson Quave's tutorial

Swift 2

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

答案 5 :(得分:22)

您必须从要在UI上运行的更新中分离出要在后台运行的更改:

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

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

答案 6 :(得分:19)

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

答案 7 :(得分:19)

Swift 4.x

将此文件放入某些文件:

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

答案 8 :(得分:17)

快捷键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
    }
}

答案 9 :(得分:9)

但是答案很好,无论如何我想分享我的面向对象的解决方案最新的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. beforeTask:()->Void在任务执行之前在UI线程上调用。
  2. backgroundTask: (param:BGParam)->BGResult
  3. 之后立即在后台线程上调用
  4. afterTask:(param:BGResult)->Void在UI线程上使用后台任务
  5. 的结果调用

答案 10 :(得分:6)

由于上面已经回答了OP问题,我只想添加一些速度考虑因素:

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

以下是来自计算密集型函数的一些实际数据,这些函数从XML文件读取(带缓冲)并执行数据插值:

设备名称/ .background / .utility / .default / .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
  4. 请注意,所有设备的数据集都不相同。它是iPhone X上最大的,也是iPhone 5s上最小的。

答案 11 :(得分:1)

我真的很喜欢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()
            }
        }
    }
}

答案 12 :(得分:1)

Grand Central Dispatch用于在我们的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

答案 13 :(得分:0)

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

答案 14 :(得分:0)

线程的多用途功能

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
}

答案 15 :(得分:-3)

在Swift 4.2中有效。

// open the client's connection
        private static DocumentClient client = new DocumentClient(
            new Uri(endpoint),authKey,
            new ConnectionPolicy { ConnectionMode = ConnectionMode.Direct, ConnectionProtocol = Protocol.Tcp });

[FunctionName("Search")]