Whither dispatch_once in Swift 3?

Since Swift 1.x, Swift has been using dispatch_once behind the scenes to perform thread-safe lazy initialization of global variables and static properties.

So the static var above was already using dispatch_once, which makes it sort of weird (and possibly problematic to use it again as a token for another dispatch_once. In fact there’s really no safe way to use dispatch_once without this kind of recursion, so they got rid of it. Instead, just use the language features built on it:

// global constant: SomeClass initializer gets called lazily, only on first use
let foo = SomeClass()

// global var, same thing happens here
// even though the "initializer" is an immediately invoked closure
var bar: SomeClass = {
    let b = SomeClass()
    b.someProperty = "whatever"
    b.doSomeStuff()
    return b
}()

// ditto for static properties in classes/structures/enums
class MyClass {
    static let singleton = MyClass()
    init() {
        print("foo")
    }
}

So that’s all great if you’ve been using dispatch_once for one-time initialization that results in some value — you can just make that value the global variable or static property you’re initializing.

But what if you’re using dispatch_once to do work that doesn’t necessarily have a result? You can still do that with a global variable or static property: just make that variable’s type Void:

let justAOneTimeThing: () = {
    print("Not coming back here.")
}()

And if accessing a global variable or static property to perform one-time work just doesn’t feel right to you — say, you want your clients to call an “initialize me” function before they work with your library — just wrap that access in a function:

func doTheOneTimeThing() {
    justAOneTimeThing
}

See the migration guide for more.

Leave a Comment