383

如何在swift中使用线程?

dispatchOnMainThread:^{

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

}];
4

17 回答 17

795

斯威夫特 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 开始,Apple 不支持上述语法,无需进行一些修改。传递QOS_CLASS_USER_INITIATED实际上不起作用,而是使用Int(QOS_CLASS_USER_INITIATED.value).

有关更多信息,请参阅Apple 文档

于 2014-07-31T23:15:43.043 回答
163

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
})
于 2016-12-06T14:25:21.737 回答
124

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

可重复使用的功能:

例如,像 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
    })
于 2015-06-15T09:13:43.997 回答
49

斯威夫特 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 的一些深入信息。

于 2016-06-16T15:13:23.300 回答
49

In Swift 4.2 and Xcode 10.1

We have three types of Queues :

1. Main Queue: Main queue is a serial queue which is created by the system and associated with the application main thread.

2. Global Queue : Global queue is a concurrent queue which we can request with respect to the priority of the tasks.

3. Custom queues : can be created by the user. Custom concurrent queues always mapped into one of the global queues by specifying a Quality of Service property (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

These all Queues can be executed in two ways

1. Synchronous execution

2. Asynchronous execution

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

From 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)
    }
}
于 2018-08-16T12:51:11.293 回答
35

来自Jameson Quave 的教程

斯威夫特 2

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
    //All stuff here
})
于 2014-06-05T09:23:47.660 回答
27

斯威夫特 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)
     }
}
于 2018-08-20T09:13:44.860 回答
25

斯威夫特 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
    }
}
于 2020-04-01T12:46:30.173 回答
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
    }
}
于 2015-07-07T08:38:20.487 回答
9

不过答案很好,无论如何我想分享我的面向对象的解决方案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 个步骤:

  1. beforeTask:()->Void在任务执行之前在 UI 线程上调用。
  2. backgroundTask: (param:BGParam)->BGResult之后立即在后台线程上调用
  3. afterTask:(param:BGResult)->Void使用后台任务的结果在 UI 线程上调用
于 2016-02-04T18:52:04.530 回答
9

由于上面已经回答了 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

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

于 2018-05-16T12:37:32.130 回答
4

多用途线程函数

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
}
于 2019-04-19T15:34:15.647 回答
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

于 2018-07-02T14:15:41.940 回答
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()
            }
        }
    }
}
于 2016-05-03T13:55:59.260 回答
0
dispatch_async(dispatch_get_global_queue(QOS_CLASS_BACKGROUND, 0), {
    // Conversion into base64 string
    self.uploadImageString =  uploadPhotoDataJPEG.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.EncodingEndLineWithCarriageReturn)
})
于 2015-11-03T07:39:05.993 回答
0

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

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)
        }
     }
}   
于 2022-02-25T14:52:31.787 回答
-1

在 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);
}
于 2018-09-22T12:52:07.363 回答