Lazy Var VS Let

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.

  1. 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.
  2. You can populate a lazy property with the value of a stored property.
  3. You can use self inside the closure of a lazy property

Swift function vs lazy var vs computed property - difference?


  • lazy vars 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 vars are only run when the property is first referred to and never again.
  • lazy vars 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:

  1. Single instantiation. Each time buttonPressed() is called, a new HeavyClass 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 if heavyClass == nil before each access.

  2. 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 to nil, 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



Leave a reply



Submit