Swift中Lazy var和var as-a-closure之间的区别

时间:2018-10-15 20:34:52

标签: swift lazy-initialization

我创建了一些示例项目,以测试各种类型的变量实现,以测试仅执行一次,每次执行一次的变量

class Something:NSObject
{
    var clock:Int = 0
    override var description: String
    {
        let desc = super.description
        clock += 1
        return "\(desc) Clock: \(clock)"
    }
}

static var staticVar:Something
{
    print("static Var")
    return Something()
}
static var staticVar2:Something = {
    print("static Var II")
    return Something()
}()

lazy var lazyVar:Something = {
    print("lazy Var")
    return Something()
}()

var simpleVar:Something {
    print("simple Var")
    return Something()
}

var simpleVar2:Something = {
    print("simple Var II")
    return Something()
}()

然后在viewDidLoad()中(以确保变量已被初始化),调用所有var几次并保存在数组中以保持强引用

var strongArr = [Something]()

print("== STATIC VAR")
strongArr.append(ViewController.staticVar)
print(strongArr.last!.description)
strongArr.append(ViewController.staticVar)
print(strongArr.last!.description)
strongArr.append(ViewController.staticVar)
print(strongArr.last!.description)

print("\n== STATIC VAR {}()")
strongArr.append(ViewController.staticVar2)
print(strongArr.last!.description)
strongArr.append(ViewController.staticVar2)
print(strongArr.last!.description)
strongArr.append(ViewController.staticVar2)
print(strongArr.last!.description)

print("\n== SIMPLE VAR")
strongArr.append(self.simpleVar)
print(strongArr.last!.description)
strongArr.append(self.simpleVar)
print(strongArr.last!.description)
strongArr.append(self.simpleVar)
print(strongArr.last!.description)

print("\n== SIMPLE VAR {}()")
strongArr.append(self.simpleVar2)
print(strongArr.last!.description)
strongArr.append(self.simpleVar2)
print(strongArr.last!.description)
strongArr.append(self.simpleVar2)
print(strongArr.last!.description)

print("\n== LAZY VAR {}()")
strongArr.append(self.lazyVar)
print(strongArr.last!.description)
strongArr.append(self.lazyVar)
print(strongArr.last!.description)
strongArr.append(self.lazyVar)
print(strongArr.last!.description)

这是在控制台中注销的结果

== STATIC VAR
static Var
<_TtCC8DemoDemo14ViewController9Something: 0x600003725100> Clock: 1
static Var
<_TtCC8DemoDemo14ViewController9Something: 0x600003725160> Clock: 1
static Var
<_TtCC8DemoDemo14ViewController9Something: 0x600003725270> Clock: 1

== STATIC VAR {}()
static Var II
<_TtCC8DemoDemo14ViewController9Something: 0x6000037251b0> Clock: 1
<_TtCC8DemoDemo14ViewController9Something: 0x6000037251b0> Clock: 2
<_TtCC8DemoDemo14ViewController9Something: 0x6000037251b0> Clock: 3

== SIMPLE VAR
simple Var
<_TtCC8DemoDemo14ViewController9Something: 0x600003725240> Clock: 1
simple Var
<_TtCC8DemoDemo14ViewController9Something: 0x6000037252a0> Clock: 1
simple Var
<_TtCC8DemoDemo14ViewController9Something: 0x6000037252b0> Clock: 1

== SIMPLE VAR {}()
<_TtCC8DemoDemo14ViewController9Something: 0x600003738100> Clock: 1
<_TtCC8DemoDemo14ViewController9Something: 0x600003738100> Clock: 2
<_TtCC8DemoDemo14ViewController9Something: 0x600003738100> Clock: 3

== LAZY VAR {}()
lazy Var
<_TtCC8DemoDemo14ViewController9Something: 0x60000372ea70> Clock: 1
<_TtCC8DemoDemo14ViewController9Something: 0x60000372ea70> Clock: 2
<_TtCC8DemoDemo14ViewController9Something: 0x60000372ea70> Clock: 3

基于这些测试,如果两个变量都定义为闭包(最后为()),则看起来懒变量和简单变量之间没有区别。

作为闭包的变量实现会自动使变量变懒还是我缺少什么?

2 个答案:

答案 0 :(得分:1)

区别在于运行变量的初始化代码的时间。对于.order_by(F('round_date').desc(nulls_last=True)) vars,初始化代码在该变量的首次访问时运行。对于implementation 'com.gdacciaro:iosdialog:1.0.3' var,它是在初始化struct / class时运行的。

lazy

输出:

non-lazy

请注意如何首先初始化非延迟struct N { lazy var a: Int = { print("Setting A"); return 5}(); var b: Int = { print("Setting B"); return 5 }() } var n = N() print(n.a) print(n.b) Setting B Setting A 5 5 仅在访问时初始化。无论哪种情况,每个属性的初始化程序仅运行一次。

答案 1 :(得分:1)

当您将它们与struct /类的其他属性混合使用时,它们会变得更加有趣。这是我想到的几个:

var-as-closure无法引用其他实例变量

struct Person {
    var firstName: String
    var lastName: String

    lazy var fullName1 = "\(firstName) \(lastName)"             // OK
    var fullName2: String = { "\(firstName) \(lastName)" }()    // invalid

    init(firstName: String, lastName: String) {
        self.firstName = firstName
        self.lastName = lastName
    }
}

原因是在初始化期间对var-as-closure进行了评估,而Swift不保证将首先初始化哪个属性。初始化firstName时,lastNamefullName2可能尚未初始化。

您不能定义包含惰性var的结构的常量实例

let p = Person(firstName: "John", lastName: "Smith")
print(p.fullName1)                                      // runtime error

您第一次读lazy var时会计算得出,因此根据定义,它会改变结构。因此let p = Person(...)是无效的。您必须使用var p = Person(...)

但是,如果Person是一个类,则可以使用let p = Person(...),因为这里的“ constant”表示p指向固定的内存地址,但是该地址处的对象可以随时更改