First, this article understates the danger significantly. It's not just that your token loader might be called twice, if you call this from two different threads you're fully in undefined behavior. Swift is "safe-ish" in that it's mostly safe in single-threaded contexts, but with data races that breaks down. It's even more confusing because some things are properly atomic (reference counts, manipulation of value types like arrays), but some aren't (access to fields in classes).
Second, the language is missing basic features that in modern programming would help tame this beast - the most important of which is a wrapper for internally mutable state that is protected by a mutex. Grand Central Dispatch can help with some of this.
Third, there are unexpected performance losses. For example, the closure for running a block on a sync "queue" is heap allocated (because the type of such a closure is the same for sync and async, and of course the latter has to be heap allocated). This will probably be fixed, but I think is symptomatic.
Fourth, there's no official concurrency model. Again, it's confusing because there are some things that are obviously intended to run with concurrency. In fairness, Rust doesn't have a formal concurrency model yet either, but it is straightforward to apply reasoning from C++, and also reasonable to expect guarantees if the primitives such as Mutex, channels, etc., are used properly.
Fifth (and related), there are no atomics in the language or the standard library. Apparently OSAtomic is deprecated, and they now recommend the use of C atomics, but you're in the territory about having to reason about the polyglot combination of Swift and C.
Likely all this will improve, but in the meantime it's important to realize how immature Swift's concurrency is.