Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a way to tell if a lazy var has been initialized?

I don't want to initialize a view controller until I need to display its view., so I have it in a lazy var like:

lazy var foo: NSViewController! = {
    let foo = NSViewController()
    foo.representedObject = self.representedObject
    return foo
}()

// ...

override var representedObject: Any? {
    didSet {
        if foo != nil {
            foo.representedObject = representedObject
        }
    }
}

self.representedObject is set before foo is ever referenced, but every time I call if foo != nil, it initializes foo :c

Is there any way I can test if foo has already been set?

like image 379
Ky. Avatar asked Nov 28 '16 15:11

Ky.


People also ask

How does swift define lazy VAR?

You indicate a lazy stored property by writing the lazy modifier before its declaration. You must always declare a lazy property as a variable (with the var keyword), because its initial value might not be retrieved until after instance initialization completes.

Do you have to initialize variables in Swift?

Variables and constants do not require initialization when declared. However, the variable or constant requires type annotation so that when the compiler reads the code line-by-line, it can determine the data type at the time of the build. A Use of undeclared type error will be thrown otherwise.

Why Lazy Cannot be used on a let?

You can't make it lazy let because lazy properties must always be variables. Because the actual value is created by evaluation, you need to declare its data type up front. In the case of the code above, that means declaring the property as Int .

Is Lazy thread safe Swift?

Another problem is that lazy var is not thread-safe which means the closure can get executed multiple times due to accesses from different threads.


2 Answers

A shorter version that uses Swift's built-in lazy semantics:

struct Foo {
    lazy var bar: Int = {
        hasBar = true
        return 123
    }()
    private(set) var hasBar = false
}

Just check for hasBar instead.

like image 61
Daniel Avatar answered Nov 16 '22 03:11

Daniel


lazy is just a convenience wrapper around one specific lazy-instantiation pattern (and one that is only moderately useful). If you want your own pattern, don't use lazy; just build it yourself.

private var _foo: NSViewController? = nil
var foo: NSViewController {
    if let foo = _foo {
        return foo
    }

    let foo = NSViewController()
    foo.representedObject = self.representedObject
    _foo = foo
    return foo
}

// This can be private or public, as you like (or you don't technically need it)
var isFooLoaded: Bool {
    return _foo != nil
}

override var representedObject: Any? {
    didSet {
        if !isFooLoaded {
            foo.representedObject = representedObject
        }
    }
}

This is designed to follow the isViewLoaded pattern, which addresses the same basic problem.

like image 20
Rob Napier Avatar answered Nov 16 '22 02:11

Rob Napier