3

In swift3 document. It is recommended to use lazy by the two following ways:

1. directly init

`lazy var someViews: UILabel = UILabel()`

2. init with block

    lazy var overlayView: UILabel = { [unowned self] in
        let overlayView = UILabel()
        overlayView.backgroundColor = self.backgroundColor.withAlphaComponent(0.90)
        overlayView.font = UIFont.boldSystemFont(ofSize: YFCalendarOverlaySize)
        overlayView.textColor = self.overlayTextColor
        overlayView.alpha = 0.0
        overlayView.textAlignment = .center
        overlayView.translatesAutoresizingMaskIntoConstraints = false
        return overlayView
    }()

If I want to lazily initialize some variable with some default value. I can only use the 2nd way. But that seems too clumsy. So, I use the following method to initialize the lazy var. It runs ok. But is it really okay? I want some help.

class SomeViewController: UIViewController {
    lazy var someViews: UILabel = self.initSomeViews()

    override func viewDidLoad() {
        print(self.someViews)
    }
}

fileprivate extension SomeViewController {

    func initSomeViews() -> UILabel! {
        let overlayView = UILabel()
        overlayView.backgroundColor = UIColor.white.withAlphaComponent(0.90)
        overlayView.font = UIFont.boldSystemFont(ofSize: YFCalendarOverlaySize)
        overlayView.alpha = 0.0
        overlayView.textAlignment = .center
        overlayView.translatesAutoresizingMaskIntoConstraints = false
        return overlayView
    }
}
1
  • "(...) I can only use the 2nd way. But that seems too clumsy.", no, actually it is a perfectly reasonable way to do so, while "So, I use the following method to initialize the lazy var. It runs ok. But is it really okay?", that is the clumsy solution here, I'm afraid :( Commented May 4, 2017 at 14:00

3 Answers 3

2

I advice NOT to use the closure variant:

lazy var overlayView: UILabel = { [unowned self] in
    let overlayView = UILabel()
    // ...
    return UILabel()
}()

Why?

I made a small research myself. Follow this link to read the detailed description.

Proper usage with function:

class SomeViewController: UIViewController {

    lazy var label: UILabel = self.getLabel()
}

fileprivate extension SomeViewController {

    func getLabel() -> UILabel {
        return UILabel()
    }
}
Sign up to request clarification or add additional context in comments.

6 Comments

I've read your post, that's good for this problem. So. In this case, is it necessary to use "[unowned self] in" in my "initSomeViews" function?
@JasonYu unowned is not required. I've updated post with proper usage micro example
If I use self.title to set the default text in the getLabel() method, then is unowned required? If not, where is unowned required?
unowned is not required. But it is a very interesting question about unowned. This question requires a deeper understanding of capture list and etc...
you should post some other question about unowned/weak and etc
|
1

Yes thats okay but your initSomeViews() has same concept as of using blocks. You can either directly assign a clouser to it or a method for that.

Note:

If you use your lazy property in viewDidLoad: then there is no need for declaring it as lazy.

-They are initialised just once and never computed again, that is they don't get computed dynamically.

1 Comment

Thanks a lot. But would you like to share your Answer link? Is your answer part of the swift documentation?
1

As a matter of safety and style (I probably gonna be downvoted for this…) I savor using implicitly unwrapped optionals for this:

private var someViews: UILabel!

override func viewDidLoad() {
    self.someViews = createSomeViews()
}

private func createSomeViews() -> UILabel { ... }

Safety. Running your initialization at once, on viewDidLoad method, buys you a nice deterministic code path across your view controller setup. Conversely, using lazy you might have more than one code path that triggers the var creation, potentially hiding nasty latent bugs (e.g. think cross-dependencies in your views, etc).

Style. What can I say? It just looks better in the eyes :)

But, if your var initialization contains some costly computation that you want to postpone as much as possible, than lazy is the way to go!

3 Comments

I don't know why anybody would down vote you on that. It's the same pattern that I use for variables that rely on the user interface having been loaded. You could lazy init them and hope they don't get referenced before the view has loaded, but, as you say, it could introduce nasty non deterministic bugs.
Thanks for the feedback @JeremyP :)
What about lazy private var someViews: UILabel = { return self.createSomeViews() }() or something similar? Having an implicitly unwrapped optional that can be referenced before viewDidLoad() (think about init(with:)) would be potentially dangerous, isn't it?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.