What does main.sync in global().async mean?

Ryan picture Ryan · Mar 13, 2017 · Viewed 10.6k times · Source

In Swift, I used this kind of pattern sometimes.

DispatchQueue.global().async {
    // do stuff in background, concurrent thread

    DispatchQueue.main.sync {
        // update UI
    }
}

The purpose of this pattern is clear. Do time consuming calculation in global thread so UI is not locked and update UI in main thread after calculation is done.

What if there's nothing to calculate? I just found a logic in my project which

//A
DispatchQueue.main.sync {
    // do something
}

crashes but

// B
DispatchQueue.global().async {
    DispatchQueue.main.sync {
        // do something
    }
}

doesn't crash.

How are they different? And Is case B different with just this?

// C
DispatchQueue.main.async {
    // do something
}

And one more question. I know main thread is serial queue, but if I run multiple code block in multiple main.async, it works like concurrent queue.

DispatchQueue.main.async {
    // do A
}

DispatchQueue.main.async {
    // do B
}

If main thread is really a serial queue, how can they run simultaneously? If it is just a time slicing than how are they different with global concurrent queue other than main thread can update UI?

Answer

Mindaugas picture Mindaugas · Mar 13, 2017

x.sync means that the calling queue will pause and wait until the sync block finishes to continue. so in your example:

DispatchQueue.global().async {
    // yada yada something
    DispatchQueue.main.sync {
        // update UI
    }
    // this will happen only after 'update UI' has finished executing
}

Usually you don't need to sync back to main, async is probably good enough and safer to avoid deadlocks. Unless it is a special case where you need to wait until something finishes on main before continuing with your async task.

As for A example crashing - calling sync and targeting current queue is a deadlock (calling queue waits for the sync block to finish, but it does not start because target queue (same) is busy waiting for the sync call to finish) and thats probably why the crash.

As for scheduling multiple blocks on main queue with async: they won't be run in parallel - they will happen one after another. Also don't assume that queue == thread. Scheduling multiple blocks onto the same queue, might create as many threads as system allow. Just the main queue is special that it utilises Main thread.