29

I'm a beginner and I sort of understand Lazy Var vs. Let. I've noticed that it saves a ton of memory usage when using Lazy Var especially with ImageViews. But the tutorials and guides I've seen so far don't use Lazy Var very often, so I'm feeling suspicious that it is bad practice and that I'm overlooking something.

I did a little research and learned that Lazy isn't "thread safe," but I don't understand what this means. I've seen a lot of pros and cons, but I can't draw any conclusions especially because I have very limited knowledge.

When is it ok (or better) to use Lazy Var vs. Let when creating a UIView?

lazy var profileImageView: UIImageView = {

    let imageView = UIImageView(image: #imageLiteral(resourceName: "page1"))
    imageView.translatesAutoresizingMaskIntoConstraints = false
    imageView.contentMode = .scaleAspectFit
    return imageView

}()
1
  • Here's an older (looks to be Swift 1) explanation of what a lazy var is. Specifically look at the section on when to use it: mikebuss.com/2014/06/22/lazy-initialization-swift Now, looking through the three related links in the right hand column of your question that suggest they are similar to your's I find that none really answer the question - like the above link - on *when to use each one. They either explain what lazy is (and why you have to use var or why something doesn't build. I'm up-voting this hopeing that somebody here can give you a good answer to a good question Commented Nov 18, 2017 at 15:45

4 Answers 4

41

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

Sign up to request clarification or add additional context in comments.

Comments

11

Another advantage to using a lazy var is improving the readability of your code.

In your example, the code related to the image view is grouped together instead of being spread out to an initializer, setup function, or viewDidLoad. This improves local reasoning by not requiring the reader of the code to venture to various places in the code to understand how your view is configured. To learn about your view, they only need to jump to its declaration.

An initialization closure marked as a lazy var can access self, allowing for more configuration to be done inside the closure, such as adding target actions or referencing other constant properties.

I would consider initializing properties (especially views) with closures as lazy var's to be a good practice, and it seems to be gaining popularity in the Swift community as well.

Depending on the project, saving developer time can be much more valuable than saving system memory.

Comments

5

The use of lazy vars can provide a workaround to a paradoxical problem: You want to create a custom view that has subviews whose initialization refers to the parent view.

For example, if you want to create a subclass of UIView that contains a child UIScrollView of the same size, you can't declare a class containing:

var m_scrollView: UIScrollView

override init(frame: CGRect)
{
    m_scrollView = UIScrollView(frame: self.frame)
    super.init(frame: frame)
}

The compiler will complain that you're referring to self before calling super.init. But... super.init has to be called after all members are initialized.

The solution to this circular problem is making m_scrollView lazy and initalizing it in its declaration:

lazy var m_scrollView = UIScrollView(frame: self.frame)

1 Comment

I tend to use lazy in these cases sometimes. However, I am not sure if this can lead to some strange bugs later on. I would rather add a setup method for the UIScrollView using constraints instead of using lazy init here.
0

I think that lazy var is worse than let.

Disadvantages:

  1. lazy var is mutable. let tells to developer that this property would not be mutated. lazy var tells that it initialized after self and it can mutate. If property is some kind of view, it usually not modified, so the developer would be misled with lazy var. The code should be self-describing;
  2. lazy var is not thread safe. So there’s a danger of multiple initialization under certain circumstances;
  3. Lazy instance properties can’t have setter observers.
  4. It can make harder debugging performance concerns;
  5. It can produce unexpected behaviour;
  6. It can produce races with multiple circular dependencies;
  7. More work in runtime - each time a lazy variable is accessed, Swift needs to check if the variable has already been initialized;
  8. In case of initializing UI, it would produce a little delay.

When I think need to use lazy var:

  1. When initial value might be expensive to generate so you’d like to avoid generating it unless it is actually needed;
  2. When there is a chance of not computing the property at all;
  3. When there is no other option but to use self. (rarely);
  4. Has circular dependencies.

Relying your question about using lazy var for views:

All part of views usually used now or later, so you not taking an advantage with lazy var. Big imageView initializing later and it just delay the memory initializing. For every view there is a setup function where you set .backgroundColor and make a layout. Anyway you would check it when read the class. So if the only reason for using lazy var is to have self in order to use something like addTarget, or arrangedSubviews, it's a bad idea because not worth the disadvantages it entails.

let is the best choose for UI elements.

Links:

2 Comments

While lazy var is not thread safe, it's not an issue in the OP's case since the question is about creating UIView instances (most likely in a UIViewController) so all initialization will be done on the main queue.
@HangarRash yeap, but however it should be for completeness of the picture.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.