Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift lazy instantiating using self

I have something that really puzzles me, specifically the following code triggers a compiler error "unresolved identifier self", and I am not sure why this is happening, as lazy means that at the time the property will be used, the class is already instantiated. Am I missing something?

Many thanks in advance.

Here is the code

class FirstClass {
    unowned var second: SecondClass

    init(second:SecondClass) {
        self.second = second
        print("First reporting for duty")
    }

    func aMethod() {
        print("First's method reporting for duty")
    }
}


class SecondClass {

    lazy var first = FirstClass(second: self)

    func aMethod() {
        first.aMethod()
    }
}
like image 946
Razvan Soneriu Avatar asked Jun 30 '16 09:06

Razvan Soneriu


People also ask

How do you declare lazy property in Swift?

You indicate a lazy stored property by writing the lazy modifier before its declaration. You must always declare a lazy property as a variable (with the var keyword), because its initial value might not be retrieved until after instance initialization completes.

What is lazy initialization in Swift?

lazy initialisation is a delegation of object creation when the first time that object will be called. The reference will be created but the object will not be created. The object will only be created when the first time that object will be accessed and every next time the same reference will be used.

When should I use lazy var Swift?

Lazy variables allow you to delay the initialisation of stored properties. This can be useful to only perform expensive work when it's actually needed. The different between lazy- and computed properties is important in cases you need to have calculations based on the current state of values.

Why Lazy Cannot be used on a let?

You cannot declare a lazy constant (lazy let) because then its value could not change. A computed property cannot be a lazy variable. This is because a computed property is always recalculated when it is called. The initialization of a lazy variable is not an atomic operation.


1 Answers

For some reason, a lazy property needs an explicit type annotation if its initial value refers to self. This is mentioned on the swift-evolution mailing list, however I cannot explain why that is necessary.

With

lazy var first: FirstClass = FirstClass(second: self)
//            ^^^^^^^^^^^^

your code compiles and runs as expected.

Here is another example which demonstrates that the problem occurs also with structs, i.e. it is unrelated to subclassing:

func foo(x: Int) -> Int { return x + 1 }

struct MyClass {
    let x = 1

    lazy var y = foo(0)            // No compiler error
    lazy var z1 = foo(self.x)      // error: use of unresolved identifier 'self'
    lazy var z2: Int = foo(self.x) // No compiler error
}

The initial value of y does not depend on self and does not need a type annotation. The initial values of z1/z2 depend on self, and it compiles only with an explicit type annotation.

Update: This has been fixed in Swift 4/Xcode 9 beta 3, lazy property initializers can now reference instance members without explicit self, and without explicit type annotation. (Thanks to @hamish for the update.)

like image 193
Martin R Avatar answered Oct 08 '22 14:10

Martin R