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

Ans*_*hul 298 multithreading ios swift dispatch-queue

如何在swift中使用线程?

dispatchOnMainThread:^{

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

}];
Run Code Online (Sandbox Code Playgroud)

tob*_*sdm 675

Swift 3.0+

很多已经在Swift 3.0中进行了现代化改造.在后台线程上运行一些东西看起来像这样:

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")
    }
}
Run Code Online (Sandbox Code Playgroud)

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")
    })
})
Run Code Online (Sandbox Code Playgroud)

Pre Swift 1.2 - 已知问题

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

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

  • 如果有人想要更像Swift的语法,我已经创建了[**Async**](https://github.com/duemunk/async),它为语法添加了一些糖,比如`Async.background {}` (23认同)

Dal*_*ord 118

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

可重复使用的功能:

例如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?()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

注:雨燕2.0,更换QOS_CLASS_USER_INITIATED.value以上QOS_CLASS_USER_INITIATED.rawValue代替

用法:

A.要在后台运行一个延迟3秒的进程:

    backgroundThread(3.0, background: {
            // Your background function here
    })
Run Code Online (Sandbox Code Playgroud)

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
    })
Run Code Online (Sandbox Code Playgroud)

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

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

  • 非常好.请您确认,延迟仅适用于完成块.这意味着A中的延迟没有影响,并且后台块立即执行而没有延迟. (2认同)

fro*_*ouo 81

Dan Beaulieu在swift3中的回答.

Swift 3.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()
                })
            }
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

用法

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
})
Run Code Online (Sandbox Code Playgroud)


Sai*_*ira 42

Swift 3版

Swift 3利用新DispatchQueue类来管理队列和线程.要在后台线程上运行某些东西,您将使用:

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

或者如果你想要两行代码:

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."
    }
}
Run Code Online (Sandbox Code Playgroud)

您还可以在本教程中获得有关Swift 3中GDC的一些深入信息.


ale*_*lex 35

来自Jameson Quave的教程

斯威夫特2

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), {
    //All stuff here
})
Run Code Online (Sandbox Code Playgroud)

  • 只是为了澄清,为什么要使用它而不是接受的答案?这只是一个较旧的API吗? (3认同)

iOS*_*iOS 26

在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
Run Code Online (Sandbox Code Playgroud)

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

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()
})
Run Code Online (Sandbox Code Playgroud)

来自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)
    }
}
Run Code Online (Sandbox Code Playgroud)


Xys*_*Xys 24

斯威夫特 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()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

用法 :

Dispatch.background {
    // do stuff

    Dispatch.main { 
        // update UI
    }
}
Run Code Online (Sandbox Code Playgroud)


phu*_*gle 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
    }
}
Run Code Online (Sandbox Code Playgroud)


Had*_*šić 21

Swift 4.x

把它放在一些文件中:

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

func main(work: @escaping () -> ()) {
    DispatchQueue.main.async {
        work()
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在需要的地方拨打电话:

background {
     //background job
     main {
       //update UI (or what you need to do in main thread)
     }
}
Run Code Online (Sandbox Code Playgroud)


Nik*_*tin 9

但是很好的答案,无论如何我想分享我的面向对象的解决方案更新为swift 3.

请检查出来: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'
Run Code Online (Sandbox Code Playgroud)

例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
Run Code Online (Sandbox Code Playgroud)

它有2种通用类型:

  • BGParam - 执行时发送给任务的参数类型.
  • BGResult - 背景计算结果的类型.

    当您创建AsyncTask时,您可以将这些类型传递到后台任务所需的任何类型,但如果您不需要这些类型,则可以将其标记为未使用,只需将其设置为:Void或者使用较短的语法:()

执行异步任务时,它将执行3个步骤:

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

  • 这对我很有用.干得好,为什么不把它放在github上? (4认同)

Cos*_*min 7

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


小智 6

线程的多用途函数

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)
    }
Run Code Online (Sandbox Code Playgroud)

像这样使用它:

performOn(.Background) {
    //Code
}
Run Code Online (Sandbox Code Playgroud)