---
title: "Queueing up async jobs"
slug: queueing-up-async-jobs
section: tech
date: 2016-09-12T12:46:00.000Z
canonical: https://roland.leth.ro/blog/tech/queueing-up-async-jobs
---

I recently had this problem: at the start of the app there's a call to fetch some reference data, on which other calls depend, but it shouldn't hinder the app launch itself, nor anything else that doesn't depend on it. So, after several approaches, I decided to use `DispatchGroups`.

First, a `struct` to abstract a `DispatchQueue` and a `DispatchGroup`:

```swift
struct Queue {

  let group = DispatchGroup()
  let queue: DispatchQueue

  init(label: String) {
    queue = DispatchQueue(label: label)
  }

}
```

This class should have a way to add a closure to the queue, that won't require waiting, basically just abstracting `async(execute:)`:

```swift
func add(_ closure: () -> Void) {
  queue.async(execute: closure)
}
```

And also a way to add a closure to the queue, that will require waiting:

```swift
func addAndWait(_ closure: () -> Void) {
  // Dispatch on our queue
  queue.async {
    self.group.enter()
    // Fire up the closure
    closure()
    // And wait for the leave call
    _ = self.group.wait(timeout: DispatchTime.distantFuture)
  }
}

func advance() { // Any form of synonym for continue, I guess
  group.leave()
}
```

Using it feels rather straightforward:

```swift
let queue = Queue(label: "com.rolandleth.demoapp.loadQueue")

queue.addAndWait {
  API.fetchReferenceData { _ in
    print("fetched 1")
    queue.advance()
  }
}

queue.add {
  API.fetchResource1 { _ in
    print("fetched 2")
  }
}

queue.addAndWait {
  self.timeConsumingJob()
  print("1")
  queue.advance()
}

queue.add {
  print("2")
}

queue.addAndWait {
  API.fetchResource2 { _ in
    print("fetched 3")
    queue.advance()
  }
}

queue.add {
  self.jobDependantOnResource2()
  print("3")
}
```

This would print out:

```swift
fetched 1
fetched 2
1
2
fetched 3
3

// Or if timeConsumingJob() finishes faster than fetchResource1():
fetched 1
1
2
fetched 2
fetched 3
3
```

I'm sure this isn't perfect, and won't work for everyone, but it should serve some purpose, nonetheless. `DispatchSemaphore` would have also worked, and so would have subclassing `NSOperationQueue`, but I found this shorter and easier to abstract. One could improve this by passing a custom `timeout` and a custom `DispatchQoS`, for example.