在swift中延迟加载属性

我试图用Swift语言来包装我的头。 在Objective-C的代码中构build视图时的常见模式是重写UI属性,并像这样延迟加载它们:

@property(nonatomic, strong) UILabel *myLabel; - (UILabel *)myLabel { if (!_myLabel) { _myLabel = [[UILabel alloc] initWithFrame:CGRectMake(20.0f, 75.0f, 320.0f, 20.0f)]; [_myLabel setFont:[UIFont subHeadlineFont]]; [_myLabel setTextColor:[UIColor subHeadlineColor]]; [_myLabel setText:@"Hello World"]; } return _myLabel; } - (void)viewDidLoad { [super viewDidLoad]; [self.view addSubview:self.myLabel]; } 

这允许UIElements的configuration在其设置中自包含,但不会导致每次重新configuration它们。

看来我们没有在Swift中访问后备存储,而@lazy关键字实际上并没有相同的语义。

我很好奇,如果有人在Swift中发现了一个相似的模式,那么允许将variables和常量的configuration和它们的声明一起以一种整齐的语法方式保存,而不会导致每次重新configuration。

我认为用闭包初始化一个lazy属性将工作:

 lazy var myLabel: UILabel = { var temporaryLabel: UILabel = UILabel() ... return temporaryLabel }() 

正如我读“Swift编程语言”(棋盘格示例),封闭仅评估一次)。

 class Thingy { init(){ println("making a new Thingy") } } var thingy = { Thingy(); }() println("\(self.thingy)") println("\(self.thingy)") 

日志消息“制作一个新的Thingy”只出现一次,certificate只有一个Thingy被创build – 封闭只被调用一次,即初始化这个属性。 这实际上是你所描述的。 所有你需要做的就是添加更多的closures,以configuration它返回的对象。

如果你使用var @lazy并且注释掉println语句,那么就不会创buildThingy,这certificate了懒惰是做它打算做的。 你可以省略这个,但是,因为你知道这个标签实际上总是需要提前。 @lazy是阻止封闭被调用,除非调用getter,但是你总是要调用getter,所以在你的情况下是毫无意义的。

这几乎是你的ObjectiveC例子的Swift版本。 (简化为使用Int而不是视图)

 class Foo { var _value: Int? var value: Int { get { if !_value { _value = 123 } return _value! } } } Foo().value //-> 123 

虽然不是很漂亮

苹果似乎做的不同…如果我在Xcode中创build一个新的项目,并添加核心数据,在AppDelegate.swift有一个例子:

 // Returns the managed object model for the application. // If the model doesn't already exist, it is created from the application's model. var managedObjectModel: NSManagedObjectModel { if !_managedObjectModel { let modelURL = NSBundle.mainBundle().URLForResource("MyApp", withExtension: "momd") _managedObjectModel = NSManagedObjectModel(contentsOfURL: modelURL) } return _managedObjectModel! } var _managedObjectModel: NSManagedObjectModel? = nil 

虽然,这个读给我看,因为variables是在初始化时创build的,不过随后读取和@lazy看起来像一个更好的实现。 有什么想法吗?

所以我试过这个:

 class TestClass { @lazy var myLabel : UILabel = { var temporaryLabel : UILabel = UILabel() return temporaryLabel }() var testLabel: UILabel { if !_testLabel { _testLabel = UILabel() } return _testLabel! } var _testLabel: UILabel? = nil func test () { println(myLabel) println(self.testLabel) } } 

而这两者确实只是懒洋洋地创造出来的。 正如@bradlarson 在Twitter上指出的那样 :

@runmad你的方法保留的一件事是属性的只读状态。 让@lazy不能用,这是一个问题。

就像ChristianOtkjær的答案一样,也可以为@lazy var指定一个类方法:

 class MyClass { @lazy var myLabel : UILabel = MyClass.newLabel() class func newLabel() -> UILabel { var temporaryLabel : UILabel = UILabel() ... return temporaryLabel } } 

这与使用闭包完全相同,但是如果闭包中的代码行数太多,则可以在声明所有属性和初始化方法后,将该代码放在其他位置的类方法中。

您可以在@lazyvariables上提供一个闭包来声明它应该如何创build:

 class Blah { @lazy var label: () -> UILabel = { var view:UILabel = UILabel(); //Do stuff here return view; } } 

Swift 3.0

我更喜欢这种内联风格。

 lazy var myLabel: UILabel = self.createMyLabel() private func createMyLabel() -> UILabel { let mylabel = UILabel() // ... return mylabel }