Static computed variable gets instantiated more than once

Static properties can be computed but also lazy, depending how you write them out.

- computed meaning that their value will be re-calculate each time they are called:

private static var dateFormatter: NSDateFormatter {
    print("here here") // prints each time dateFormatter its called
    let formatter = NSDateFormatter()
    formatter.dateFormat = "EEEE h a"
    return formatter
}

- lazy meaning that their value will be calculated once and only the first time they are called:

private static var dateFormatter: NSDateFormatter = {
    print("here here") // prints only one time, when called first time
    let formatter = NSDateFormatter()
    formatter.dateFormat = "EEEE h a"
    return formatter
}()

It took me a while to find this question when attempting to figure out the difference between a static computed property in Swift that does include = and () and one that does not. @dan did a good job explaining what one should do to ensure a static property is computed only once, but in my own experimentation I came up with the following example that helped me visualize the differences between the two uses.

static var foo: String {
    print("computing foo")
    return "foo"
}

static var bar: String = {
    print("computing bar")
    return "bar"
}()

for _ in 1...3 {
    print(Class.foo)
    print(Class.bar)
}

The end result is:

computing foo
foo
computing bar
bar
computing foo
foo
bar
computing foo
foo
bar

foo has the benefits of a static property, including association with the type rather than a particular instance and the inability to be overridden by a subclass. bar, however, goes further by ensuring the property is only ever calculated one time.


Your snippet is equivalent to a get-only property, basically it's the same as:

private static var dateFormatter: NSDateFormatter {
    get {
        print("here here")
        let formatter = NSDateFormatter()
        formatter.dateFormat = "EEEE h a"
        return formatter
    }
}

If you only want it to run once you should define it the same way you would define a lazy property:

private static var dateFormatter: NSDateFormatter = {
    print("here here")
    let formatter = NSDateFormatter()
    formatter.dateFormat = "EEEE h a"
    return formatter
}()