Question: (Perhaps answered by [How does a serial dispatch queue guarantee resource protection?](https://stackoverflow.com/q/19010732/1449799) but I don't understand how)

**Question**

How does gcd know when an asynchronous task (e.g. network task) is finished? Should I be using `dispatch_retain` and `dispatch_release` for this purpose? **Update:** I cannot call either of these methods with ARC... What do?

**Details**

I am interacting with a 3rd party library that does a lot of network access. I have created a wrapper via a small class that basically offers all the methods i need from the 3rd party class, but wraps the calls in `dispatch_async(serialQueue) { () -> Void in` (where `serialQueue` is a member of my wrapper class).

I am trying to ensure that each call to the underlying library finishes before the next begins (somehow that's not already implemented in the library).

Answer: 
As mentioned before, `DispatchGroup` is a very good mechanism for that.

You can use it for synchronous tasks:

```
let group = DispatchGroup()
DispatchQueue.global().async(group: group) {
   syncTask()
}

group.notify(queue: .main) {
    // done
}

```

It is better to use `notify` than `wait`, as `wait` does block the current thread, so it is safe on non-main threads.

You can also use it to perform async tasks:

```
let group = DispatchGroup()
group.enter()
asyncTask {
   group.leave()
}

group.notify(queue: .main) {
    // done
}

```

Or you can even perform any number of parallel tasks of any synchronicity:

```
let group = DispatchGroup()

group.enter()
asyncTask1 {
   group.leave()
}

group.enter() //other way of doing a task with synchronous API
DispatchQueue.global().async {
   syncTask1()
   group.leave()
}

group.enter()
asyncTask2 {
   group.leave()
}

DispatchQueue.global().async(group: group) {
   syncTask2()
}

group.notify(queue: .main) {
    // runs when all tasks are done
}

```

It is important to note a few things.

1. Always check if your asynchronous functions call the completion callback, sometimes third party libraries forget about that, or cases when your `self` is `weak` and nobody bothered to check if the body got evaluated when `self` is `nil`. If you don't check it then you can potentially hang and never get the notify callback.
2. Remember to perform all the needed `group.enter()` and `group.async(group: group)` calls before you call the `group.notify`. Otherwise you can get a race condition, and the `group.notify` block can fire, before you actually finish your tasks.

> 
> BAD EXAMPLE
> 
> 
> 

```
let group = DispatchGroup()

DispatchQueue.global().async {
   group.enter()
   syncTask1()
   group.leave()
}

group.notify(queue: .main) { 
    // Can run before syncTask1 completes - DON'T DO THIS
}

```
The answer to the question in your questions body:

> 
> I am trying to ensure that each call to the underlying library finishes before the next begins 
> 
> 
> 

A serial queue *does* guarantee that the tasks are progressed in the order you add them to the queue.

---

I do not really understand the question in the title though:

> 
> *How* does a serial queue ... *know* when a task is complete?
> 
> 
>