通过将属性设置为nil,在Swift中再次触发lazy初始化器

我想要一个懒惰初始化属性的初始化我可以再次调用,如果我把属性设置为零。

如果我这样定义我的财产:

lazy var object = { /*init code*/ }() 

…后来调用该属性,初始化器被触发一次。 但是,如果我在程序中稍后将object设置为零,则不会再次调用初始化程序。 我怎么能在Swift中做到这一点?

我看着计算的属性,但他们并没有实际存储的值,所以每当我调用variables,总是发生计算或初始化。 我只想计算只有财产是无。

lazy属性初始值设定程序负责在读取模式下首次初始化属性。 设置为零对初始化状态没有影响 – 这只是属性存储的有效值。

你可以用3个属性来模仿一个懒惰的初始化:

  • 一个私有的初始化器,作为一个计算的属性实现(或者如果你愿意,可以closures)
  • 一个私人支持属性,存储实际值
  • 一个非私人的财产,这是你实际使用你的代码

代码如下所示:

 class MyClass { private var _myPropInitializer: Int { return 5 } private var _myProp: Int? var myProp: Int? { get { if self._myProp == nil { self._myProp = self._myPropInitializer } return _myProp! } set { _myProp = newValue } } } 
  • initializer属性在需要初始化的时候返回一个variables的计算值,这是上面例子中的5整数
  • myProp是一个可选的整数(可以存储一个nil ):
    • 在设置时,它会将新值存储在_myProp属性中
    • 得到,如果_myPropnil ,它调用初始化,分配给_myProp ,它返回它的值

如果你想重用这个模式,最好把所有东西都放在一个类中:

 class Lazy<T> { private let _initializer: () -> T private var _value: T? var value: T? { get { if self._value == nil { self._value = self._initializer() } return self._value } set { self._value = newValue } } required init(initializer: () -> T) { self._initializer = initializer } } 

注意: struct是不可用的,因为不允许在属性getter中设置属性,而在类中则是这样。

那么你可以使用它如下:

 class MyTestClass { var lazyProp: Lazy<Int> init() { self.lazyProp = Lazy( { return 5 } ) } } 

操场上的一些testing:

 var x = MyTestClass() x.lazyProp.value // Prints {Some 5} x.lazyProp.value = nil x.lazyProp._value // Prints nil x.lazyProp.value // Prints {Some 5} 

缺点是你必须访问x.lazyProp.value的实际属性,而不是x.lazyProp

当你的对象只能是nil或计算值的时候,这是一个懒惰的模式。 它只需要2个属性:

 var todayPredicate: NSPredicate! { set { guard newValue == nil else {return} // could throw here if required self._todayPredicateLazyBacker = nil } get { guard self._todayPredicateLazyBacker == nil else {return self. _todayPredicateLazyBacker} // construct your today predicate let predicate = ... self._todayPredicateLazyBacker = predicate return self._todayPredicateLazyBacker } } private var _todayPredicateLazyBacker: NSPredicate? 

todayPredicate一次被读取时只构造一次(懒惰)。

那么你为什么要把todayPredicate设置为零? 在这个例子中,你可能正在观察当天的变化,因为todayPredicate必须总是代表今天。 在您的观察员代码中,您可以简单地执行此操作,例如…

 self.todayPredicate = nil self.loadEvents()