问题
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?
回答1:
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.
回答2:
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)
回答3:
Optional and lazy properties are not the same
- An optional property is used when there are chances that the value might not be available(i.e can be nil). But in your scenario, the navigation bar will always be available, its just that the user might not open it.
- So using a lazy property serves your purpose. The NavigationBar will only be initialised if the user taps on it.
I do not see any performance issues except that if you use an optional, there is an additional overhead of checking if the value is nil each time before accessing it.
来源:https://stackoverflow.com/questions/34816203/swift-lazy-and-optional-properties