accessQueue.async(flags: .barrier, execute: { }) will dispatch the block to the isolation queue.
The async part means it will return before actually executing the block (which performs the write), which means we can continue processing.
The .barrier flag means that it will wait until every currently running block in the queue is finished executing before it executes. Other blocks will queue up behind it and be executed when the barrier dispatch is done.
When the barrier is executing, it essentially acts as a serial queue. That is, the barrier is the only thing executing. After the barrier finishes, the queue goes back to being a normal concurrent queue. Here's when you would and wouldn't use barrier functions:
- Custom Serial Queue: A bad choice here; barriers won't do anything helpful since a serial queue executes one operation at a time anyway.
- Global Concurrent Queue: Use caution here; this probably isn't the best idea since other systems might be using the queues and you don't want to monopolize them for your own purposes.
- Custom Concurrent Queue: This is a great choice for atomic or critical areas of code. Anything you're setting or instantiating that needs to be thread-safe is a great candidate for a barrier.