I want to use Lazy initialization for some of my properties in Swift. My current code looks like this:
lazy var fontSize : CGFloat = {
if (someCase) {
return CGFloat(30)
} else {
return CGFloat(17)
}
}()
The thing is that once the fontSize is set it will NEVER change. So I wanted to do something like this:
lazy let fontSize : CGFloat = {
if (someCase) {
return CGFloat(30)
} else {
return CGFloat(17)
}
}()
Which is impossible.
Only this works:
let fontSize : CGFloat = {
if (someCase) {
return CGFloat(30)
} else {
return CGFloat(17)
}
}()
So - I want a property that will be lazy loaded but will never change.
What is the correct way to do that? using let
and forget about the lazy init? Or should I use lazy var
and forget about the constant nature of the property?
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.
You can't use lazy with let . You can't use it with computed properties . Because, a computed property returns the value every time we try to access it after executing the code inside the computation block. You can use lazy only with members of struct and class .
Lazy properties are also useful when the initial value for a property requires complex or computationally expensive setup that shouldn't be performed unless or until it's needed. The example below uses a lazy stored property to avoid unnecessary initialization of a complex class.
Swift has a mechanism built right into the language that enables just-in-time calculation of expensive work, and it is called a lazy variable. These variables are created using a function you specify only when that variable is first requested.
This is the latest scripture from the Xcode 6.3 Beta / Swift 1.2 release notes:
let constants have been generalized to no longer require immediate initialization. The new rule is that a let constant must be initialized before use (like a var), and that it may only be initialized: not reassigned or mutated after initialization.
This enables patterns like:
let x: SomeThing
if condition {
x = foo()
} else {
x = bar()
}
use(x)
which formerly required the use of a var, even though there is no mutation taking place. (16181314)
Evidently you were not the only person frustrated by this.
Swift book has the following note:
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. Constant properties must always have a value before initialization completes, and therefore cannot be declared as lazy.
This makes sense in the context of implementing the language, because all constant stored properties are computed before initialization of an object has finished. It does not mean that the semantic of let
could have been changed when it is used together with lazy
, but it has not been done, so var
remains the only option with lazy
at this point.
As far as the two choice that you presented go, I would decide between them based on efficiency:
var lazy
let
Note: I would further optimize your code to push the conditional into CGFloat
initializer:
let fontSize : CGFloat = CGFloat(someCase ? 30 : 17)
As dasblinkenlight points out lazy properties should always be declared as variables in Swift. However it is possible make the property read-only so it can only be mutated from within the source file that the Entity was defined in. This is the closest I can get to defining a "lazy let".
private(set) lazy var fontSize: CGFloat = {
if someCase {
return 30
} else {
return 17
}
}()
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