如何在swift中使用线程?
dispatchOnMainThread:^{
NSLog(@"Block Executed On %s", dispatch_queue_get_label(dispatch_get_current_queue()));
}];
]
?
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." } }
斯威夫特 3.0+
Swift 3.0 中有很多内容modernized。在后台队列上运行一些东西看起来像这样:
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 开始,Apple 不支持上述语法,无需进行一些修改。传递 QOS_CLASS_USER_INITIATED
实际上不起作用,而是使用 Int(QOS_CLASS_USER_INITIATED.value)
。
有关详细信息,请参阅 Apples documentation
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
})
background
闭包中的工作非常非常长(〜=无限)。此方法将持续有限时间:您的后台作业需要执行的时间。因此,一旦您的后台作业执行时间 + 延迟过去,completion
闭包就会被调用。
最佳实践是定义一个可以多次访问的可重用函数。
可重复使用的功能:
例如,像 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 秒 - 注意使用没有背景参数的完成参数:
backgroundThread(3.0, completion: {
// Your delayed function here to be run in the foreground
})
if(background != nil){ background!(); }
替换为 background?()
以获得更快捷的语法吗?
DispatchQueue.global(priority: Int(DispatchQoS.QoSClass.userInitiated.rawValue)).async {
,但这会引发类似 cannot invoke initializer for type 'Int' with an argument list of type '(qos_class_t)'
的错误。找到了一个可行的解决方案 here (DispatchQueue.global(qos: DispatchQoS.QoSClass.userInitiated).async
)。
在 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)
}
}
.background
QoS 或 .userInitiated
时,我没有看到任何变化,但对我来说,使用 .background
斯威夫特 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 的一些深入信息。
斯威夫特 2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
//All stuff here
})
斯威夫特 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)
}
}
斯威夫特 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
}
}
您必须将要在后台运行的更改与要在 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_main_queue()) { // update some UI }
?
由于上面已经回答了 OP 问题,我只想添加一些速度注意事项:
我不建议以 .background 线程优先级运行任务,尤其是在 iPhone X 上,任务似乎分配在低功耗内核上。
以下是计算密集型函数的一些真实数据,该函数从 XML 文件(带缓冲)读取并执行数据插值:
设备名称/.background/.utility/.default/.userInitiated/.userInteractive
iPhone X: 18.7s / 6.3s / 1.8s / 1.8s / 1.8s iPhone 7: 4.6s / 3.1s / 3.0s / 2.8s / 2.6s iPhone 5s: 7.3s / 6.1s / 4.0s / 4.0s / 3.8 s
请注意,并非所有设备的数据集都相同。它在 iPhone X 上是最大的,在 iPhone 5s 上是最小的。
虽然答案很好,但无论如何我想分享我的面向对象解决方案 Up to date for 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
它有 2 种通用类型:
BGParam - 执行时发送给任务的参数类型。
BGResult - 后台计算结果的类型。当您创建 AsyncTask 时,您可以将这些类型设置为您需要传入和传出后台任务的任何类型,但如果您不需要这些类型,则可以将其标记为未使用,只需将其设置为:Void 或使用更短的语法: ()
执行异步任务时,会经过 3 个步骤:
beforeTask:()->Void 在任务执行之前在 UI 线程上调用。 backgroundTask: (param:BGParam)->BGResult 在 afterTask:(param:BGResult)->UI 线程上调用后立即在后台线程上调用,结果来自后台任务
多用途线程函数
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
}
我真的很喜欢 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()
}
}
}
}
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
下面的代码是否有缺点(当需要在之后启动前景屏幕时)?
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)
}
}
}
dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0), {
// Conversion into base64 string
self.uploadImageString = uploadPhotoDataJPEG.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.EncodingEndLineWithCarriageReturn)
})
在 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);
}
Async.background {}
之类的语法添加了一些糖