Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift Lazy and Optional properties

What is the difference between a Lazy or Optional property in Swift?

For example, if someone is building a navigation bar that comes in from the side, I think that should all be within one UIViewController. The user might never open the menu but sometimes they will.

var menu: NavigationBar?
lazy var menu: NavigationBar = NavigationBar.initialize()

Both of the optional I think are good code, because they don't create the view unless its needed. I understand Optional means there might be a value it might be nil. I also understand Lazy means don't worry about it until I need it.

Specific Question

My question is are their performance patterns (safety and speed) that say optionals are faster and safer or vise versa?

like image 223
Cody Weaver Avatar asked Jan 15 '16 17:01

Cody Weaver


People also ask

What are lazy properties in Swift?

A lazy stored property is a property whose initial value isn't calculated until the first time it's used. You indicate a lazy stored property by writing the lazy modifier before its declaration.

What is the difference between computed property and lazy property?

Swift's lazy properties let us delay the creation of a property until it's actually used, which makes them like a computed property. However, unlike a computed property they store the result that gets calculated, so that subsequent accesses to the property don't redo the work.

Can we capture a lazy variable inside a closure or not?

Important to note: You can use self inside the closure of a lazy property. It will not cause any retain cycles.

What are type properties in Swift?

There are two kinds of properties: stored properties and computed properties. Stored properties are properties that are stored in the class's instance. Stored properties store constant and variable values. Computed properties are for creating custom get and set methods for stored properties.


2 Answers

OK, this is an interesting question, and I don't want to imply that the existing answers aren't good, but I thought I'd offer my take on things.

lazy variables are great for things that need to be setup once, then never re-set. It's a variable, so you could change it to be something else, but that kind of defeats the purpose of a lazy variable (which is to set itself up upon demand).

Optionals are more for things that might go away (and might come back again). They need to be set up each time.

So let's look at two scenarios for your side menu: one where it stays around while it's not visible, and another for when it is deallocated.

lazy var sideMenu = SideMenu()

So the first time the sideMenu property is accessed, SideMenu() is called and it is assigned to the property. The instance stays around forever, even when you're not using it.

Now let's see another approach.

var _sideMenu: SideMenu?
var sideMenu: SideMenu! {
    get {
        if let sm = _sideMenu {
            return sm
        } else {
            let sm = SideMenu()
            _sideMenu = sm
            return sm
        }
    }
    set(newValue) {
        _sideMenu = newValue
    }
}

(Note this only works for classes, not structs.)

OK so what does this do? Well it behaves very similarly to the lazy var, but it let's you re-set it to nil. So if you try to access sideMenu, you are guaranteed to get an instance (either the one that was stored in _sideMenu or a new one). This is a similar pattern in that it lazily loads SideMenu() but this one can create many SideMenu() instances, where the previous example can only create one once.

Now, most view controllers are small enough that you should probably just use lazy from earlier.

So two different approaches to the same problem. Both have benefits and drawbacks, and work better or worse in different situations.

like image 78
Ash Furrow Avatar answered Oct 21 '22 03:10

Ash Furrow


They're actually pretty different.

Optional means that the value could possibly be nil, and the user isn't guaranteeing that it won't be. In your example, var menu: NavigationBar? could be nil for the entire lifetime of the class, unless something explicitly assigns it.

Lazy on the other hand means that the assignment will not be called until it is first accessed, meaning that somewhere in code someone tries to use your object. Note however that it is STILL promised to not be nil if you declare it like you have here lazy var menu: NavigationBar = NavigationBar.initialize(), so no need to do optional chaining.

And actually, a variable can be BOTH Lazy AND Optional, which means that it's value will be loaded when it is first accessed, and that value might be nil at the point it's initialized or at any future point. For example:

lazy var menu: NavigationBar? = NavigationBar.initialize()

That NavigationBar.initialize() is now allowed to return nil, or someone in the future could set the menu to be nil without the compiler/runtime throwing errors!

Does that make the difference clear?

Edit: As to which is BETTER that's really a case by case thing. Lazy variables take a performance hit on first initialization, so the first access will be a slow one if the initialization process is long. Otherwise, they're nearly identical in terms of safety/performance. Optional variables you have to unwrap before using and so there is a very minor performance cost with that (one machine instruction, not worth the time to think about)

like image 4
tbondwilkinson Avatar answered Oct 21 '22 04:10

tbondwilkinson