Sadly, multithreading, asynchrony, and concurrency are areas of programming that really have no beginner version. libdispatch is a library that makes it easier, and has many nice features, but it doesn't change the fact that it's fundamentally complex and subtle.
Apple's concurrency guide is as good a place to start as any, but here's a semi-brief summary that I wrote up in response to a question earlier:
In a serial program (which is the "normal" way most people write programs), every thing that happens is ordered with respect to every other thing; that is, each thing happens before or after each other thing. In a concurrent program, we can selectively break that ordering, allowing things to happen independently from other things (multi-core processors take advantage of this to make things faster by running multiple independent things simultaneously). libdispatch provides a set of functions and types for managing the order in which things happen:
By far the most common use for this is to make it so that the main thread of your application (where your UI is running) does not wait for a long-running background task to complete, so that your app can stay responsive even when it's doing things. Another common use is to split tasks into chunks that can run simultaneously, to take advantage of multiple cores.
The danger is that many things you take for granted absolutely require a total ordering. If you do this, for example:
var x:Int = 5 dispatch_async(queue_one) { x++ } dispatch_async(queue_two) { x++ } println(x)
the program may print 5, 6 or 7! This is because the x++ operation is actually several steps (load current value, add one, save new value), so you can end up with your program doing this:
queue_one loads 5 queue_two loads 5 queue_one adds 1 to the value it loaded, yielding 6 queue_two adds 1 to the value it loaded, yielding 6 queue_one stores 6 queue_two stores 6 println(6)
Or even
println(5) //there's no guarantee that a dispatch_async()'d block will run any code at all before the original thread runs more code
queue_one loads 5
queue_two loads 5
queue_one adds 1 to the value it loaded, yielding 6
queue_two adds 1 to the value it loaded, yielding 6
queue_one stores 6
queue_two stores 6
when what you wanted was this:
queue_one loads 5 queue_one adds 1 to the value it loaded, yielding 6 queue_one stores 6 queue_two loads 6 queue_two adds 1 to the value it loaded, yielding 7 queue_two stores 7 println(7)
One of the reasons Swift focuses so heavily on immutable and pass-by-value types is that these are MUCH easier to work with in concurrent programs. If you can't share mutable state, then you can't have two threads or queues stomp all over each others changes, by definition.