The other answers here and around the interwebs are pretty great, but I feel this little tidbit should also be mentioned:
The great thing about dispatch_once
was how optimized it was, essentially nixing the code after the first run in a way that I hardly understand, but am reasonably assured that would be that much faster than setting and checking a (real) global token.
While the token thing could be reasonably implemented in Swift, having to declare yet another stored boolean isn't all that great. Not to mention thread-unsafe. As the doc says, you should use a "lazily initialized global." Yeah, but why clutter up the global scope, right?
Until somebody convinces me of a better method, I tend to declare my do-once closure inside the scope I'll be using it in, or reasonably close thereto, as follows:
private lazy var foo: Void = {
// Do this once
}()
Basically I'm saying that "When I read this, foo
should be the result of running this block." It behaves the exact same way as a global let
constant would, just in the right scope. And prettier. Then I'd call it wherever I'd like, by reading it into something that'll never be used otherwise. I like Swift's _
for that. Like so:
_ = foo
This really cool quirk has actually been around a while, but hasn't seen much love. It basically leaves the variable alone at runtime, as an uncalled closure, until something wants to see its Void
result. On read, it calls the closure, throws it away and keeps its result in foo
. Void
uses practically nothing memory-wise, so subsequent reads (i.e. _ = foo
) do nothing on the CPU. (Don't quote me on that, somebody please check up on the assembly to be sure!) Have as many as you like, and Swift basically quits caring about it after the first run! Lose that old dispatch_once_t
, and keep a lot of your code as pretty as when you first opened it Christmas day!
My one issue is that you can set foo
to something else before its first read, and then your code will never be called! Hence the global let
constant, which prevents that. Thing is, constants in class scope don't play well with self
, so no playing with instance variables... But seriously, when do you set anything to Void
anyway??
That, and you'd need to specify the return type as Void
or ()
, else it'll still complain about self
. Who'da thunk?
And lazy
is just to make the variable as lazy as it should be, so Swift doesn't run it straight off on init()
.
Pretty snazzy, so long as you remember not to write to it! :P
private
to the class' constructors? Notice that if have a variable in this class you could have multiple instances holding a different value for this variable. Once the constructor isprivate
, only thestatic let singleton
line would be able initialize it. – Deaconry