通过将property设置为nil,再次在Swift中触发延迟初始化程序

Mat*_*ros 15 iphone cocoa-touch ipad ios swift

我想要一个lazily-initialized属性,如果我将属性设置为nil,我可以再次调用它.

如果我这样定义我的属性:

lazy var object = { /*init code*/ }()
Run Code Online (Sandbox Code Playgroud)

...然后调用属性,初始化程序被触发一次.但是,如果我object稍后在程序中设置为nil,则不会再次调用初始值设定项.我怎么能在Swift中做到这一点?

我查看了计算属性但它们实际上并不存储值,所以每当我调用变量时,总会发生计算或初始化.我只想在属性为零时计算.

Ant*_*nio 16

惰性属性初始化程序负责在读取模式下第一次访问属性时初始化该属性.设置为nil对初始化状态没有影响 - 它只是属性存储的有效值.

您可以使用3个属性模仿延迟初始化:

  • 私有初始值设定项,实现为计算属性(如果您愿意,还可以使用闭包)
  • 私有后备属性,存储实际值
  • 非私有属性,它是您在代码中实际使用的属性

代码如下所示:

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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)
  • 初始化属性在需要初始化时返回变量的计算值,这是5上例中的整数
  • myProp是一个可选的整数(以便能够存储nil):
    • 在set上,它会将新值存储在_myProp属性中
    • on get,如果_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
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:a struct不可用,因为不允许在属性getter中设置属性,而在类中则是.

然后你可以使用它如下:

class MyTestClass {
    var lazyProp: Lazy<Int>

    init() {
        self.lazyProp = Lazy( { return 5 } )
    }
}
Run Code Online (Sandbox Code Playgroud)

在操场上的一些测试:

var x = MyTestClass()
x.lazyProp.value // Prints {Some 5}
x.lazyProp.value = nil
x.lazyProp._value // Prints nil
x.lazyProp.value // Prints {Some 5}
Run Code Online (Sandbox Code Playgroud)

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