Why Does My @Lazy Property Crash, But If I Make It Non Lazy It Works

Why does my @lazy property crash, but if I make it non lazy it works?

After some trial, I found something quite odd.

First of all, if we wrap the var inside a class, it simply works:

class RegionManager {
@lazy var enteredRegions = Array<String>()
}

In AppDelegate, I declared a @lazy var regManager = RegionManager().

Then, in application:didFinishLaunching:, I modify and use the value, it works without spitting a word:

regManager.enteredRegions.append("New!")
println("Regions: \(regManager.enteredRegions)") // Regions: [New!]

After this, I tried to change to some native values, for example, String, Int and so on, they all fail.

So, my guess is that this strange behaviour is actually a bug of the compiler itself, it may be rooted in some optimization for native types, maybe there's a inner pool or what that apple doesn't tell us.

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

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.

Lazy module variables--can it be done?

You can't do it with modules, but you can disguise a class "as if" it was a module, e.g., in itun.py, code...:

import sys

class _Sneaky(object):
def __init__(self):
self.download = None

@property
def DOWNLOAD_PATH(self):
if not self.download:
self.download = heavyComputations()
return self.download

def __getattr__(self, name):
return globals()[name]

# other parts of itun that you WANT to code in
# module-ish ways

sys.modules[__name__] = _Sneaky()

Now anybody can import itun... and get in fact your itun._Sneaky() instance. The __getattr__ is there to let you access anything else in itun.py that may be more convenient for you to code as a top-level module object, than inside _Sneaky!_)



Related Topics



Leave a reply



Submit