iOS Swift - Grand Central Dispatch (2)

1. Dispatch Groups

  • With Dispatch Groups, you can group together multiple tasks
  • You can either wait for them to complete or receive a notification once they finish
  • Tasks can be asynchronous or synchronous and can even run on different queues.

2. Using dispatch groups with synchronous wait() method

// 1
DispatchQueue.global(qos: .userInitiated).async {
var storedError: NSError?

// 2
let dispatchGroup = DispatchGroup()

for address in [
   "https://www.ayavn.us/images/8a2d61ef0eeaef65eb5cf5d82d87cc63603dcdea038f925c95d39b59e221611e.jpg",
   "https://www.ayavn.us/images/8a2d61ef0eeaef65eb5cf5d82d87cc63603dcdea038f925c95d39b59e221611e.jpg",
   "https://www.ayavn.us/images/8a2d61ef0eeaef65eb5cf5d82d87cc63603dcdea038f925c95d39b59e221611e.jpg",
] {
   guard let url = URL(string: address) else { return }

   // 3
   dispatchGroup.enter()

   let photo = DownloadRemoteImage(url: url) { _, error in
      storedError = error

      // 4
      dispatchGroup.leave()
   }
}   

// 5      
dispatchGroup.wait()

// 6
DispatchQueue.main.async {
   completion?(storedError)
}   
}
  • The synchronous wait method blocks the current thread. Thus, you need to use DispatchQueue.main.async to place the entire method into a background queue. This ensures you don’t block the main thread.

  • Create a new dispatch group.

  • Call enter() to manually notify the group that a task has started. You must balance out the number of enter() calls with the number of leave() calls, or your app will crash.
  • Notify the group that this work is done.
  • Call wait() to block the current thread while waiting for tasks’ completion. This waits forever — which is fine because the photos creation task always completes. You can use wait(timeout:) to specify a timeout and bail out on waiting after a specified time.
  • At this point, you know that all image tasks have either completed or timed out. You then make a call back to the main queue to run your completion closure.

3. Using dispatch groups with asynchronous method (notify(queue:work:))

var storedError: NSError?

// 2
let dispatchGroup = DispatchGroup()

for address in [
   "https://www.ayavn.us/images/8a2d61ef0eeaef65eb5cf5d82d87cc63603dcdea038f925c95d39b59e221611e.jpg",
   "https://www.ayavn.us/images/8a2d61ef0eeaef65eb5cf5d82d87cc63603dcdea038f925c95d39b59e221611e.jpg",
   "https://www.ayavn.us/images/8a2d61ef0eeaef65eb5cf5d82d87cc63603dcdea038f925c95d39b59e221611e.jpg",
] {
   guard let url = URL(string: address) else { return }

   dispatchGroup.enter()

   let photo = DownloadRemoteImage(url: url) { _, error in
      storedError = error
      dispatchGroup.leave()
   }
}  

// 2    
downloadGroup.notify(queue: DispatchQueue.main) {
   completion?(storedError)
}
  • You don’t need to put the method in an async call since you’re not blocking the main thread.
  • notify(queue:work:) serves as the asynchronous completion closure. It runs when there are no more items left in the group.

Comments !

Links

Social