Dispatch Framework
Dispatch for Android and iOS - Working with concurrency and background threads in Android and iOS
Introduction
The dispatch framework is a library for writing code for asynchronous processing. It allows you to run code in the background and invoke functions asynchronously. SCADE ported the dispatch framework to Android and ensures that is works on x86/ARM for both 32 and 64bit.
Your Swift code is 100% same for both iOS and Android. There are no difference.
Example Code
Please see the UgSystemDemo/Dispatch project for the source code created in this chapter. See Installing examples for information on how to download the examples.
Understanding dispatch
This is not a full tutorial on the advanced concepts of dispatch, but a simple example driven guide. There are many other articles out on the internet to read. Here are some examples. Please ensure that you understand concepts such as DispatchQueue,work item.
- Apple documentation https://developer.apple.com/documentation/dispatch
- TheSwiftDev https://theswiftdev.com/2018/07/10/ultimate-grand-central-dispatch-tutorial-in-swift/
Getting started
So our goal is to run code asynchronously. You can queue your code for execution and Dispatch takes care of the correct sequence of execution based on priorities:
Queues
The queues you deal most with are the main queue and the global queue:
The main queue
- is used for UI tasks
- is a serial queue, that means tasks are queued and executed one after the other
The global queue
- is used for stuff that is non-UI related
- is a concurrent queue, that means the tasks are executed in parallel
- is used for non-ui tasks such as IO and database operations, long running calculations
// Use global queue to execute code asynchronously in the background
DispatchQueue.global(qos: .background).async {
print("background: \(Thread.current)")
}
Run tasks in the main queue. There are not many good reasons to use the main queue alone. Most of the time we use it to update the UI with results from a long running task:
DispatchQueue.global(qos: .background).async {
// do your long running background job here
print("running long running iO job : background: \(Thread.current)")
DispatchQueue.main.async {
// then update your UI here
}
}
Queue priorities - Quality of Service
The code that you want to execute asynchronously is called task or work item in Dispatch speak. The priority with which the code is executed depends on the quality of service settings. There are four different quality of services
- .userInteractive (highest priority)
- .userInitiated
- .utility
- .background (lowest priority)
Executing code with delay
Dispatch has many other functionalities. From instance, tell Dispatch to run a task only after some time.
// run tasks in background with delay
let inTwoSeconds = DispatchTime.now() + .seconds(2)
DispatchQueue.global(qos: .background).asyncAfter(deadline: inTwoSeconds) {
print("ran this after two seconds : background: \(Thread.current)")
}
Canceling a long running task
Let's say you are retrieving data, but for some reason need to interrupt this long running process. You use the DispatchWorkItem class to achieve this
// Example 4: Cancel a tasks after some time.
// Create task that runs for long time
var myWorkItem : DispatchWorkItem?
myWorkItem = DispatchWorkItem {
for i in 1...5 {
guard let item = myWorkItem, !item.isCancelled else {
print("Example 4 : workitem was canceled")
break
}
// wait one second
sleep(1)
print("Example 4: waiting \(i)")
}
}
// inform when workitem is done
myWorkItem?.notify(queue: .main) {
print("Example 4 : I am done with my job")
}
// start workitem and cancel later
let cancelAfter = DispatchTime.now() + .seconds(2)
DispatchQueue.global().asyncAfter(deadline: cancelAfter) {
myWorkItem?.cancel()
}
// Run workitem
DispatchQueue.main.async(execute: myWorkItem!)
What's next
This guide showed the fully working Dispatch framework. We appreciate your questions and comments.
Updated almost 6 years ago