14

I have a date formatter I'm trying to create as a singleton within a UITableViewCell subclass so I've created a computed property like this:

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

The problem is that I'm seeing the print statement more than once, which means it's getting created more than once. I've found other ways to do this (like putting in in an external class, or a class method), but I would love to understand what's happening here. Any ideas?

Julian B.
  • 3,605
  • 2
  • 29
  • 38

4 Answers4

32

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
}()
dan
  • 9,695
  • 1
  • 42
  • 40
  • you mean private lazy var dateFormatter: NSDateFormatter ? – Alex Kosyakov May 18 '16 at 23:02
  • It may be worth noting that if the original computed property is on a _protocol extension_, the above approach will not work because the assignment makes it a stored property and you can't store properties on protocols or their extensions. You would need to store it elsewhere (e.g. as a static var on an extension of a concrete type, etc). – David James Nov 26 '20 at 16:36
8

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.

Ian Rahman
  • 315
  • 3
  • 7
1

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
}()
denis_lor
  • 6,212
  • 4
  • 31
  • 55
0

Your static var is not a singleton, it is just a class method that creates and returns an instance of date formatter.

Check these answers of how to create a real sungleton: Using a dispatch_once singleton model in Swift

Community
  • 1
  • 1
Alex Kosyakov
  • 2,095
  • 1
  • 17
  • 25