9

In this article, it says (referencing the code below): "You must use lazy to prevent the closure for being created more than once."

private lazy var variable:SomeClass = {
    let fVariable = SomeClass()
    fVariable.value = 10
    return fVariable
}()

Why would lazy prevent the closure from being created more than once? And why would the lack of lazy cause it to evaluate more than once?

2

2 Answers 2

20

The tutorial code you quote is this:

private lazy var variable:SomeClass = {
    let fVariable = SomeClass()
    fVariable.value = 10
    return fVariable
}()

Contrast it with this:

private var variable:SomeClass {
    let fVariable = SomeClass()
    fVariable.value = 10
    return fVariable
}

The first one initializes variable to a newly created SomeClass instance, once at most (and maybe not even that many times). The second one is a read-only computed variable and creates a new SomeClass instance every time its value is read.

Sign up to request clarification or add additional context in comments.

1 Comment

I was looking at this post and the label that's lazily instantiated has a call to add it to the view before returning it. Is that correct, or should you just return the label?
13

Your intuition is right, that article is incorrect. I'm guessing the author is conflating/confusing computed property syntax with the immediately-executed-closure trick. The lazy keyword has nothing to do with how many times the closure is executed. lazy simply causes the property to remain uninitialized until first access, at which point the expression on the right hand side of the equal sign is evaluated.

To simplify, this:

var myVar: MyType {
    return MyType()
}

is very different than this:

var myVar: MyType = MyType()

which is similar in storage but has different initialization semantics than this:

lazy var myVar: MyType = MyType()

In the first example, myVar is a computed property and the code inside of the curly braces is executed every time myVar is accessed. In other words, every time you access myVar you'd get a newly created object back.

In the second example, myVar is a stored property and the expression after the equal sign is evaluated once during initialization of the class or struct that contains that property.

In the third example, myVar is still a stored property but the evaluation of the expression after the equal sign (be it an initializer expression, a function invocation, or a closure invocation) is delayed until it's accessed.

As a side note, this line of code:

lazy var myVar: MyType = { ... }()

is equivalent to:

func doStuffAndReturnMyType() { ... }
lazy var myVar: MyType = doStuffAndReturnMyType()

The shorthand in the first example wasn't specifically designed for–it just works because Swift's type system (is awesome and) treats closures as unnamed (anonymous) functions.

3 Comments

Am I right that trailing brackets not needed in this line func doStuffAndReturnMyType() { ... }()?
@ShadowOf Good catch, my mistake. I've edited the post to fix it.
Could you clarify the immediately-executed-closure trick? It seems to me that the suffixed "()" means that the property will return the return value as opposed to the closure, and i dont quite understand how the trick fits into all of this

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.