【问题标题】:Lazy property ' s memory management惰性属性的内存管理
【发布时间】:2017-05-19 15:19:40
【问题描述】:

当我学习 swift 时,我发现 Lazy 的概念有点混乱。

惰性属性在类实例需要或访问时初始化

   class Employee
        {
            var name : String
            lazy var salary = Salary(Basic : 25000 ,HRA : 3000 , DA : 4000)    
            lazy var minExperience = 0 


     init(nameValue :String)
        {
            name = nameValue 

       } }

    var emp1 = Employee("John") // Here the minExperience and 
//salary will be nil as they are not assigned any space = 

//emp1.salary.storage = nil , emp1.minExperience.storage = nil 


// now access the minExperience

emp1.minExperience // using 1st time and this will return 0 !  emp1.salary.HRA // using 1st time and this will return 3000 !

所以我的问题是:

  1. 因为 minExperiencesalary 没有分配任何存储空间,所以在我们访问它之前,它会将其值存储在哪里 - 03000 ???

  2. 惰性属性的一个方面是

    当属性的初始值依赖于外部因素时,惰性属性很有用,而外部因素的值在 实例初始化完成。

那为什么 Xcode 强制我们在声明时赋值呢??

  1. 由于我们已经为 Lazy 属性赋值,显然我们不需要在 init 方法中初始化它。

【问题讨论】:

    标签: swift properties lazy-evaluation


    【解决方案1】:
    1. 该类不存储惰性属性值。相反,它只会在您第一次引用它时初始化惰性属性:

    惰性存储属性是初始值不是 计算到第一次使用为止。

    1. 您需要在声明时分配一个值,因为编译器需要知道如何在时间到来时初始化惰性属性。但是,如果您想分配取决于实例(self)或其他对象的值,您还可以定义一个闭包,您可以在其中访问 self 以及外部因素,因为闭包是在实例初始化后调用的。

    例如,在您的示例中,您可以这样做:

    class Employee {
       var name : String
       lazy var minExperience = 0
       lazy var salary:Salary =  { [unowned self] in
           if self.name.characters.count > 0 {
               return Salary(Basic : 25000 ,HRA : 3000 , DA : 4000)
           }
           else {
               return Salary(Basic : 0 ,HRA : 0 , DA : 0)
           }
       }()
    
       init(nameValue :String) {
           name = nameValue
       } 
    }
    

    salary 是一个惰性属性,这意味着您可以在闭包中引用 self,因为在初始化完成并且知道 self 存在之前,不会访问惰性属性。

    添加了[unowned self] in 以防止泄漏。

    1. 你说得对,我们不需要在 init 方法中初始化惰性属性,因为这是惰性属性的重点,我们在初始化时不知道它们的值或者不想在初始化类中初始化。

    【讨论】:

      【解决方案2】:

      惰性变量仍然分配它需要的内存。它只是推迟初始化代码的执行。

      这是与常规变量的唯一区别,在这两种情况下,编译器都需要一个值来分配(最初或在第一次引用时)。

      在你的例子中,

      salary 似乎是惰性 var 的一个很好的候选者,因为它需要一个函数来获取初始值,并且推测该函数在您创建 Employee 对象时还没有准备好运行,或者成本太高而无法系统地执行(并且可以等待薪水变量的实际使用)

      另一方面,minExperience 没有计算其初始值,并且根本不会从懒惰中受益。

      如果我们没有惰性变量,我们可以使用内部变量和计算属性获得相同的结果:

       internal var _salary : Salary! = nil
       var salary:Salary
       {  
          get {
                 if _salary == nil
                 { _salary = Salary(Basic : 25000 ,HRA : 3000 , DA : 4000) }
                 return _salary 
              }
      
          set { _salary = newValue }
       }
      

      这(大致)说明了编译器对惰性 var 所做的工作。

      结果是一样的,但需要更多的代码。

      【讨论】:

      • 这是另一回事,我们可以对计算的属性和函数做同样的事情。 &薪水只是一个例子。我们可以有任何复杂的类。那么问题是它在哪里存储值 "25000" , "3000" , "4000" 直到初始化?
      • 延迟初始化就像一个函数,因此这些值存储在编译后的代码本身中,就像您将放在函数或函数调用中的任何其他常量一样。
      猜你喜欢
      • 1970-01-01
      • 2011-11-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-29
      • 1970-01-01
      相关资源
      最近更新 更多