斯威夫特的懒惰变种

时间:2018-03-23 01:21:56

标签: ios swift lazy-loading var let

在阅读了Swift的 lazy 变量后,我有以下问题:

class MainViewController: UIViewController {

      lazy var heavyClass = HeavyClass()

      func buttonPressed () {
         //Use heavyClass here
         self.heavyClass.doStuff()
      }    
}

所以你使用上面的lazy var来优化代码,这样就不会立即分配heavyClass。因此,在启动时,这将是最佳的,因为在启动时不会分配heavyClass。

但是,这不会与上面相同吗?

class MainViewController: UIViewController {

      var heavyClass : HeavyClass?

      func buttonPressed () {
         //Use heavyClass here
         self.heavyClass =  HeavyClass()
         self.heavyClass!.doStuff()
      }    
}

2 个答案:

答案 0 :(得分:5)

在您的示例中,结果并不完全相同,具体如下:

  1. 单一实例化。每次调用buttonPressed()时,都会实例化一个新的HeavyClass。使用lazy关键字时不是这种情况,该关键字仅在首次访问时创建实例。为了匹配惰性语义,您必须在每次访问之前检查并设置heavyClass == nil

  2. 空性。您必须通过可选链接(heavyClass)或强制解包(heavyClass?.doStuff())每次要使用heavyClass!.doStuff()时解包。您还可以将变量设置回nil,这在第一个示例中将是编译器错误。

  3. 懒惰变量的真正胜利是当你有多个使用变量的地方时。我相信你可以在这里发现重复:

    func buttonPressed() {
        if self.heavyClass == nil {
            self.heavyClass = HeavyClass()
        }
        self.heavyClass?.doStuff()
    }
    
    func aDifferentButtonPressed() {
        if self.heavyClass == nil {
            self.heavyClass = HeavyClass()
        }
        self.heavyClass?.doSomethingElse()
    }
    

    这是使用惰性变量整理的:

    func buttonPressed() {
        self.heavyClass.doStuff()
    }
    
    func aDifferentButtonPressed() {
        self.heavyClass.doSomethingElse()
    }
    

答案 1 :(得分:1)

有多种方法可以解决同样的问题,但我会在这里讨论一些问题。问题在于您只想在需要时分配内存。在某些情况下,您可能会使用这种或那种方式加上它可能会受到编码风格的影响。一方面,假设该类需要一些设置,因此使用lazy可能会提供更好的代码可读性。例如:

lazy var heavyClass: HeavyClass = {
    let heavyClass = HeavyClass()
    heavyClass.attribute1 = X
    heavyClass.attribute2 = X
    heavyClass.attribute3 = X
    heavyClass.attributeAndSoOn = X
    return heavyClass
}()

关键是,所有标准设置都是自包含的,只有在需要时你才能获得内存分配的好处。您不必添加功能或延长动作例程(例如buttonPressed)。

在另一种情况下,您可以使用选项,但这确实增加了值为零的可能性。然后你必须添加逻辑来处理这个问题。

我还看过一个强行打开的模型,但我个人并不亲自使用它。它看起来像这样:

class MainViewController: UIViewController {

  var heavyClass : HeavyClass!

  func buttonPressed () {
     //Use heavyClass here
     heavyClass = {
        let heavyClass = HeavyClass()
        // do your other stuff here
        return heavyClass
     }()
    heavyClass.doStuff()
  }    
}

这都是一个偏好问题。我会说lazy var也不是线程安全的。因此,如果您可以使用该对象拥有多个线程,则一个线程可以访问部分构造的对象。

希望这有帮助!