通过将属性设置为nil,在Swift中再次触发延迟初始化 [英] Trigger lazy initializer again in Swift by setting property to nil

查看:472
本文介绍了通过将属性设置为nil,在Swift中再次触发延迟初始化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想要一个延迟初始化的属性,如果我将属性设置为nil,我的初始化器可以再次调用。



如果我这样定义属性:

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

...和稍后调用属性,初始化器被触发一次。但是,如果我稍后在我的程序中将 object 设置为nil,则不会再次调用初始化程序。



我研究了计算属性,但是它们并不实际存储值,因此每当调用变量时,计算或初始化总是发生。我只想在属性为nil时计算。

解决方案

lazy属性初始化器负责初始化属性在读取模式下被访问。设置为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
}
}
}




  • initializer属性在需要初始化时返回变量的计算值,即 5 integer在上面的示例

  • myProp 是一个可选的整数(能够存储 nil ):

    • 在集合中,它会将新值存储在 _myProp 属性

    • 如果 _myProp nil ,它会调用初始化程序,将它分配给 _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
}
}

需要init(初始化程序:() - > T){
self._initializer = initializer
}
}

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



可以使用它如下:

  class MyTestClass {
var lazyProp:Lazy< Int>

init(){
self.lazyProp = Lazy({return 5})
}
}
pre>

在操场上进行一些测试:

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

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


I want a lazily-initialized property whose initializer I can invoke again if I set the property to nil.

If I define my property this way:

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

...and later invoke the property, the initializer is triggered once. However, if I set object to nil later in my program, the initializer is not invoked again. How can I do that in Swift?

I looked into computed properties but they don't actually store values, so whenever I invoke the variable, the computation or initialization always occurs. I want to compute only whenever the property is nil.

解决方案

The lazy property initializer is responsible of initializing the property the first time it is accessed in read mode. Setting to nil has no effect on the initialization status - it's just a valid value the property stores.

You can mimic a lazy initialization with 3 properties:

  • a private initializer, implemented as a computed property (or a closure if you prefer)
  • a private backing property, storing the actual value
  • a non private property, which is the one you actually use in your code

The code looks like this:

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
        }
    }
}

  • the initializer property returns a computed value for the variable when it needs to be initialized, which is the 5 integer in the above example
  • myProp is an optional integer (to be able to store a nil):
    • on set, it will store the new value in the _myProp property
    • on get, if _myProp is nil, it invokes the initializer, assigning it to _myProp, and it returns its value

If you want to reuse that pattern, it's better to put everything in a class:

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
    }
}

Note: a struct is not usable because setting a property inside a property getter is not allowed, whereas in a class it is.

Then you can use it as follows:

class MyTestClass {
    var lazyProp: Lazy<Int>

    init() {
        self.lazyProp = Lazy( { return 5 } )
    }
}

Some tests in playground:

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

The downside is that you have to access to the actual property as x.lazyProp.value and not as x.lazyProp.

这篇关于通过将属性设置为nil,在Swift中再次触发延迟初始化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆