Are lazy vars in Swift computed more than once? I was under the impression that they replaced the:
if (instanceVariable) {
return instanceVariable;
}
// set up variable that has not been initialized
Paradigm from Objective-C (lazy instantiation).
Is that what they do? Basically only called once the first time the app asks for the variable, then just returns what was calculated?
Or does it get called each time like a normal computed property?
The reason I ask is because I basically want a computed property in Swift that can access other instance variables. Say I have a variable called "fullName" and it just concatenates firstName
and lastName
. How would I do that in Swift? It seems like lazy vars are the only way to go, as in normal computed vars (non-lazy) I can't access other instance variables.
So basically:
Do lazy vars in Swift get called more than once? If so, how do I create a computed variable that can access instance variables? If not, if I only want a variable to be computed once for performance reasons, how do I do this?
A lazy var is a property whose initial value is not calculated until the first time it's called. It's part of a family of properties in which we have constant properties, computed properties, and mutable properties.
Lazy properties are useful when the initial value for a property is dependent on outside factors whose values are not known until after an instance's initialization is complete.
Another problem is that lazy var is not thread-safe which means the closure can get executed multiple times due to accesses from different threads.
The error message is completely useless at explaining what is going on, but essentially lazy and weak are at odds with each other: lazy tells Swift that you don't want your variable created until the first time you access it, but once it is created, you want to keep it indefinitely for future reference, while.
lazy var
s are only calculated once, the first time you use them. After that, they're just like a normal variable.
This is easy to test in a playground:
class LazyExample {
var firstName = "John"
var lastName = "Smith"
lazy var lazyFullName : String = {
[unowned self] in
return "\(self.firstName) \(self.lastName)"
}()
}
let lazyInstance = LazyExample()
println(lazyInstance.lazyFullName)
// John Smith
lazyInstance.firstName = "Jane"
println(lazyInstance.lazyFullName)
// John Smith
lazyInstance.lazyFullName = "???"
println(lazyInstance.lazyFullName)
// ???
If you'll want to recalculate it later, use a computed property (with a backing variable, if it's expensive) - just like you did in Objective-C.
No, lazy properties are initialized only once. If you set a new value, or reset to nil (for optional properties), the lazy initializer is not invoked again.
I think what you need is a computed property - it's not backed by a stored property, so it is not involved in the initialization, and as such you can refer other instance properties.
Why do you say that "normal computed vars (non-lazy) I can't access other instance variables"?
Answers stating that a lazy var can only be computed once are not true. From the documentation at https://docs.swift.org/swift-book/LanguageGuide/Properties.html, the following is stated:
If a property marked with the lazy modifier is accessed by multiple threads simultaneously and the property has not yet been initialized, there is no guarantee that the property will be initialized only once.
Also, please watch this talk: https://developer.apple.com/videos/play/wwdc2016/720/. At around 17:00, the following screen appears:
That talk gives you more insight about multithreading, I recommend you to watch it!
All the other answers are correct, I would just like to add that Apple warns about lazy
variables and concurrency:
If a property marked with the lazy modifier is accessed by multiple threads simultaneously and the property has not yet been initialized, there is no guarantee that the property will be initialized only once.
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