iOS Concurrency with GCD & Operations

Sep 12 2023 · Swift 5.8, macOS 13, iOS 16, Xcode 14.3

Part 1: Grand Central Dispatch

04. Use Dispatch Work Items

Episode complete

Play next episode

Next
About this episode
Leave a rating/review
See forum comments
Cinema mode Mark complete Download course materials
Previous episode: 03. Use Dispatch Queues Next episode: 05. Challenge: A Better Way to Download Images

Get immediate access to this and 4,000+ other videos and books.

Take your career further with a Kodeco Personal Plan. With unlimited access to over 40+ books and 4,000+ professional videos in a single subscription, it's simply the best investment you can make in your development career.

Learn more Already a subscriber? Sign in.

Heads up... You've reached locked video content where the transcript will be shown as obfuscated text.

Use a Dispatch Work Item

Often, you use a dispatch queue to “fire and forget” background tasks. If you want a lot more control over organizing and managing tasks, you’d use operations and operation queues instead — you’ll learn about these in part 3 of this course. But you can get a little more control over dispatch queue tasks with DispatchWorkItems and DispatchWorkGroups. You’ll learn about dispatch work groups in a later video.

let mainQueue = DispatchQueue.main
let userQueue = DispatchQueue.global(qos: .userInitiated)
func task1() {
  print("Task 1 started")
  sleep(4)
  print("Task 1 finished")
}
func task2() {
  print("Task 2 started")
  print("Task 2 finished")
}
userQueue.async {
  task2()
}
>> Just run task 2 in the background.
Task 2 started
Task 2 finished
let workItem = DispatchWorkItem {
  task1()
}
userQueue.async(  // choose async(execute:) from menu
userQueue.async(execute: workItem)
>> Run task 1 as a work item.
Task 1 started
Task 1 finished
if workItem.wait(timeout: .now() + 3) == .timedOut {
  print("I got tired of waiting.")
} else {
  print("Work item completed.")
}
>> Waiting for task 1...
Task 1 started
I got tired of waiting.
Task 1 finished
let backgroundWorkItem = DispatchWorkItem {
  task1()
}
let updateUIWorkItem = DispatchWorkItem {
  task2()
}
userQueue.async(execute: backgroundWorkItem)
backgroundWorkItem.notify(queue: mainQueue, 
                          execute: updateUIWorkItem)
enum Queues { case main, user }
// TODO later: Set specific key for each queue.
let specificKey = DispatchSpecificKey<Queues>()
mainQueue.setSpecific(key: specificKey, value: .main)
userQueue.setSpecific(key: specificKey, value: .user)
let backgroundWorkItem = DispatchWorkItem {
  task1()
  whichQueue(workItem: "backgroundWorkItem")
}
let updateUIWorkItem = DispatchWorkItem {
  task2()
  whichQueue(workItem: "updateUIWorkItem")
}
>> Run task 2 work item after task 1 work item finishes.
Task 1 started
Task 1 finished
>> backgroundWorkItem is running on userQueue
Task 2 started
Task 2 finished
>> updateUIWorkItem is running on mainQueue
if !updateUIWorkItem.isCancelled {
  updateUIWorkItem.cancel()
}
>> Run task 2 work item after task 1 work item finishes.
Task 1 started
>> Cancel task 2 work item before task 1 work item finishes.
Task 1 finished
>> backgroundWorkItem is running on userQueue