How to use background thread in swift?
Solution 1
Swift 3.0+
A lot has been modernized in Swift 3.0. Running something on a background queue looks like this:
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 through 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 – Known issue
As of Swift 1.1 Apple didn't support the above syntax without some modifications. Passing QOS_CLASS_USER_INITIATED
didn't actually work, instead use Int(QOS_CLASS_USER_INITIATED.value)
.
For more information see Apples documentation
Solution 2
Dan Beaulieu's answer in swift5 (also working since 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()
})
}
}
}
}
Usage
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
})
Solution 3
The best practice is to define a reusable function that can be accessed multiple times.
REUSABLE FUNCTION:
e.g. somewhere like AppDelegate.swift as a Global Function.
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?()
}
}
}
Note: in Swift 2.0, replace QOS_CLASS_USER_INITIATED.value above with QOS_CLASS_USER_INITIATED.rawValue instead
USAGE:
A. To run a process in the background with a delay of 3 seconds:
backgroundThread(3.0, background: {
// Your background function here
})
B. To run a process in the background then run a completion in the foreground:
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. To delay by 3 seconds - note use of completion parameter without background parameter:
backgroundThread(3.0, completion: {
// Your delayed function here to be run in the foreground
})
Solution 4
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)
}
}
Solution 5
Swift 3 version
Swift 3 utilizes new DispatchQueue
class to manage queues and threads. To run something on the background thread you would use:
let backgroundQueue = DispatchQueue(label: "com.app.queue", qos: .background)
backgroundQueue.async {
print("Run on background thread")
}
Or if you want something in two lines of code:
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."
}
}
You can also get some in-depth info about GDC in Swift 3 in this tutorial.
Anshul
Updated on July 08, 2022Comments
-
Anshul almost 2 years
How to use threading in swift?
dispatchOnMainThread:^{ NSLog(@"Block Executed On %s", dispatch_queue_get_label(dispatch_get_current_queue())); }];
-
tobiasdm over 9 yearsAnd if someone wants a more Swift like syntax, I've created Async that adds some sugar to the syntax like
Async.background {}
-
Zalak Patel over 9 yearsI am using your code in xCode 6.0.1 and ios 8.It gives error as "QOS_CLASS_BACKGROUND" return class and it is of type UInt32 and "dispatch_get_global_queue" requires 1st parameter as int so type error is coming.
-
Lucas Goossen over 9 yearsSo in Xcode 6.1.1 I am not getting an error for using just plain simple "QOS_CLASS_BACKGROUND". Is it fixed?
-
tobiasdm over 9 years@LucasGoossen Yes, it has been fixed. I've update the post accordingly.
-
Nikita Semenov about 9 yearsiOS 7 doesn't support this feature. So avoid it if you want older OS support
-
tobiasdm about 9 years@NikitaPronchik Isn't this clear from the answer? Else feel free to make a edit to it.
-
Allison about 9 yearsJust for clarification, why would this be used instead of the accepted answer? Is this just an older API?
-
bperdue about 9 years@Sirens I would think this would be very useful for apps supporting < iOS 8.
-
μολὼν.λαβέ about 9 yearsI use this for iOs 8.2 to force processes.
-
LoVo almost 9 yearsnice snippet, should be the correct answer. @Dale Clifford
-
Craig Grummitt over 8 yearsBrilliant high level modern Swift-y approach to access old-timey GCD methods from the low level C library. Should come standard in Swift.
-
ObjectiveTC over 8 yearsVery nice. Would you please confirm, the delay only works for the completion block. So that means that the delay in A. has no impact, and the background block executes immediately without delay.
-
justColbs over 8 yearsSo
dispatch_async(dispatch_get_main_queue()) { // update some UI }
is called when the background statement(Outer Block) is done executing? -
PostCodeism over 8 yearsDISPATCH_QUEUE_PRIORITY_DEFAULT reverts to QOS_CLASS_DEFAULT. So I guess you could say it's more high level / accepted syntax.
-
AZOM about 8 yearsWhat happens, if you add a delay to option B aswell?
-
36 By Design almost 8 yearsThis works wonderfully for me. Nice work, why not put it on github?
-
Simon Bengtsson almost 8 yearsYou should be able to replace
if(background != nil){ background!(); }
withbackground?()
for a somewhat swiftier syntax? -
Surz over 7 yearsIsn't this only for Swift 2.3 and below?
-
Dev-iL over 7 yearsCould you please update this for Swift 3? The auto converter turned it into
DispatchQueue.global(priority: Int(DispatchQoS.QoSClass.userInitiated.rawValue)).async {
but this throws an error likecannot invoke initializer for type 'Int' with an argument list of type '(qos_class_t)'
. A working solution is found here (DispatchQueue.global(qos: DispatchQoS.QoSClass.userInitiated).async
). -
Dale Clifford over 7 yearsAmazing, thank you for updating so nicely to the Swift 3.0.1 format!
-
korgx9 about 7 yearsAlso as a best practice, consider to put it in extension of UIViewController
-
Fattie about 7 yearsI use extensions more than any living person. But there's a real danger in using an extension that is no different, at all, from the original!
-
Fattie about 7 yearsSaid. Since your answer is the best, I threw in a line of code showing how you "call back when finished". Feel free to unwind or edit, cheers
-
Sentry.co about 7 years@Frouo Very elegant, is it possible to add a completion handler to when 4 async calls all finish? I know its a bit off-topic.
-
Fattie about 7 years@GitSyncApp - possibly look in to DispatchGroups for what you want. Many QA on here about it.
-
Fattie about 7 yearsyup forget that link. all you need is a dispatch group - it's very very simple; no worries at all !
-
Hernan Arber about 7 yearsWonderful! This should be the Right Answer for anyone planning on RE-USING this Background process stuff :-)
-
Dilip Jangid almost 7 yearsIt helped me but one thing i want to ask that how to run this method for infinite time in background
-
J. Doe almost 7 yearsThis won't work anymore with the newest version of swift I guess... Lots of errors when I try to add this.
-
frouo almost 7 years@DilipJangid you can't, unless your job in the
background
closure is very very very long (~=infinite). This method is made to last for a finite time: the time your background job needs to execute. So,completion
closure will be called as soon as your background job execution time + delay has passed. -
Naresh about 5 yearsBest tutorial for threads medium.com/@gabriel_lewis/…
-
Admin over 4 yearsI didn't see any changes when you use
.background
QoS or.userInitiated
but for me it worked out with.background
-
Karoly Nyisztor over 3 yearsYou may not see any difference between using .background and .userInitiated QoS because the system can override your setting and promote the .background QoS to .userInitiated. That's a behind-the-scenes optimization for queues used from within the main UI queue to make them match the QoS of the parent. You can check the QoS of the current thread using Thread.current.qualityOfService.
-
seeplusplus over 3 yearsI wish this wasn't voted down. I have been searching the web for examples on how to create actual threads without GCD in Swift, and it is very difficult to find anything. GCD isn't appropriate for my use case, and I found this little example helpful.
-
Balázs Vincze about 3 yearsBeware that you should only be using the
.background
QoS class for tasks that have low priority. Often.userInitiated
is what you are really after. -
tobiasdm about 3 yearsVery much agreed @BalázsVincze, thanks! I’ll update with
.userInitiated
since seems like a more sensible default. -
Fattie over 2 yearsDispatchQueue.main.async does not at all do something on the UX thread immediately. It simply stacks it to be done, after, other items being done are done
-
ScottyBlades over 2 yearsA DispatchQueue is not a thread.