Lazy Var vs Let
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 - Lazy Var vs. Let when creating views programmatically (saving memory)
Whether you will use lazy var
or not depends on your code and its context. It is not bad or good on its own. You have to decide when it is appropriate.
Before you can decide that, you have to know what lazy var
is.
What is lazy var
?
Lazy initialization is a concept where initialization (construction) of variable content is delayed until its first usage. First access to such variable triggers initialization. Since content is not created until variable is used (needed) using lazy initialized variables can save resources.
That is primary drive behind lazy initialization. You don't create something until you need it. That is also logic you will use when deciding whether something should be lazy var
or not.
If you are dealing with views (or anything else) that are always visible (needed) there is little point in using lazy initialization. On the other hand when you are dealing with instances that are not always needed - then using lazy var
is justified.
If your view is always visible in presented view controller, you will not accomplish much by making it lazy. If it is visible only under specific circumstances - for instance when user expands some collapsed panel - then making it lazy makes sense. It will make your view controller load faster and use less memory by default.
As far as thread safety is concerned, lazy var
are not thread safe in Swift.
That means if two different threads try to access the same lazy var
at the same time, before such variable has been initialized it is possible that one of the threads will access partially constructed instance.
You can find more about thread safety in:
Swift - is lazy var thread-safe?
Make "lazy var" threadsafe
Difference between Lazy var and var as-a-closure in Swift
The difference is when the init code for the variable is run. For lazy
vars, the init code is run on first access of that variable. For non-lazy
vars, it's run when the struct/class is initialized.
struct N {
lazy var a: Int = { print("Setting A"); return 5}();
var b: Int = { print("Setting B"); return 5 }()
}
var n = N()
print(n.a)
print(n.b)
Output:
Setting B
Setting A
5
5
Note how non-lazy b
is initialized first. a
is only initialized when it's accessed. In either case, the initializer for each property is only run once.
What is the advantage of a lazy var in Swift
Lazy Stored Property vs Stored Property
There are a few advantages in having a lazy property instead of a stored property.
- The closure associated to the lazy property is executed only if you read that property. So if for some reason that property is not used (maybe because of some decision of the user) you avoid unnecessary allocation and computation.
- You can populate a lazy property with the value of a stored property.
- You can use
self
inside the closure of a lazy property
Swift function vs lazy var vs computed property - difference?
lazy var
s are actually stored properties, so you can't put it in extensions or anywhere stored properties are not allowed.- The getter for computed properties is run every time you refer to that property. This can be significant especially if the getter is time-consuming or has side-effects to other parts of the code.
- The getter for
lazy var
s are only run when the property is first referred to and never again. lazy var
s are variables. You can mutate them.- Computed properties can optionally have a setter, so sometimes they are read-only.
- Using a function like that is very similar to a read only computed property. You just have to add
()
when getting its value.
Swift's Lazy Var
In your examples the outcomes are not quite the same, in the following ways:
Single instantiation. Each time
buttonPressed()
is called, a newHeavyClass
will be instantiated. This is not the case when using the lazy keyword, which will only create the instance on first access. To match the lazy semantics you would have to check and set ifheavyClass == nil
before each access.Nullability. You must unwrap your
heavyClass
each time you want to use it, either through optional chaining (heavyClass?.doStuff()
) or force unwrapping (heavyClass!.doStuff()
). You are also able to set the variable back tonil
, which would be a compiler error in the first example.
The real wins of lazy variables are when you have multiple places which use the variable. I'm sure you can spot the repetition here:
func buttonPressed() {
if self.heavyClass == nil {
self.heavyClass = HeavyClass()
}
self.heavyClass?.doStuff()
}
func aDifferentButtonPressed() {
if self.heavyClass == nil {
self.heavyClass = HeavyClass()
}
self.heavyClass?.doSomethingElse()
}
This is tidied up using a lazy variable:
func buttonPressed() {
self.heavyClass.doStuff()
}
func aDifferentButtonPressed() {
self.heavyClass.doSomethingElse()
}
swift lazy var use let constant
Since buttonWidth
is an instance property, the only way to access it is through an instance of JRTopView
.
You can either create a new instance and do yourInstance.buttonWidth
if you are outside this class, or just do buttonWidth/self.buttonWidth
if you are inside.
However, being a constant that will always have the same value for all instances of JRTopView
, it would make more sense to promote it to a class level:
static let buttonWidth:CGFloat = 150
This should allow you to do JRTopView.buttonWidth
.
Related Topics
Issue with Adding Node to Scene View
Store Encodables in a Swift Dictionary
Scngeometryelement Setup in Swift 3
New Firebase Retrieve Data and Put on the Tableview (Swift)
Change Time Interval in Skaction.Waitforduration() as Game Goes On
How to Get Coreml in Pure Playground Files
What Are the Advantages Swift Deprecates C-Style for Statement
What Is the Type of the Logical Operators
Subtle Cast Warning When Using SQLite.Swift ... Binding? to Any
In Swift,There's No Way to Get the Returned Function's Argument Names
Create an Outlet in Storyboard to an Inherited Property
How to Send Push Notifications Without Using Firebase Console
Opposite of _Conversion in Swift to Assign to a Value of a Different Type
If the Swift 'Guard' Statement Must Exit Scope, What Is the Definition of Scope
Timestamped Event Matching Error: Failed to Find Matching Element
Sktextureatlas No Longer Sharing Textures in iOS 10