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’re accessing parts of this content for free, with some sections shown as obfuscated text.

Heads up... You’re accessing parts of this content for free, with some sections shown as obfuscated text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

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