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()
}
}
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.
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.
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.
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.
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 struct
s, 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.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With