【问题标题】:Static computed variable gets instantiated more than once静态计算变量被实例化多次
【发布时间】:2016-09-15 14:40:16
【问题描述】:

我有一个日期格式化程序,我试图在 UITableViewCell 子类中创建一个单例,所以我创建了一个这样的计算属性:

private static var dateFormatter: NSDateFormatter {
    print("here here")
    let formatter = NSDateFormatter()
    formatter.dateFormat = "EEEE h a"
    return formatter
}

问题是我不止一次看到 print 语句,这意味着它被创建了不止一次。我找到了其他方法来做到这一点(比如放入外部类或类方法),但我很想了解这里发生了什么。有什么想法吗?

【问题讨论】:

    标签: ios swift static nsdate nsdateformatter


    【解决方案1】:

    静态属性可以是computed,也可以是lazy,具体取决于您如何写出它们。

    - computed 表示每次调用时都会重新计算它们的值:

    private static var dateFormatter: NSDateFormatter {
        print("here here") // prints each time dateFormatter its called
        let formatter = NSDateFormatter()
        formatter.dateFormat = "EEEE h a"
        return formatter
    }
    

    -lazy 表示它们的值将被计算一次,并且仅在它们第一次被调用时计算:

    private static var dateFormatter: NSDateFormatter = {
        print("here here") // prints only one time, when called first time
        let formatter = NSDateFormatter()
        formatter.dateFormat = "EEEE h a"
        return formatter
    }()
    

    【讨论】:

      【解决方案2】:

      在试图找出 Swift 中包含 =() 的静态计算属性与不包含的静态计算属性之间的区别时,我花了一段时间才找到这个问题。 @dan 很好地解释了应该做些什么来确保只计算一次静态属性,但在我自己的实验中,我想出了以下示例,帮助我可视化两种用途之间的差异。

      static var foo: String {
          print("computing foo")
          return "foo"
      }
      
      static var bar: String = {
          print("computing bar")
          return "bar"
      }()
      
      for _ in 1...3 {
          print(Class.foo)
          print(Class.bar)
      }
      

      最终结果是:

      computing foo
      foo
      computing bar
      bar
      computing foo
      foo
      bar
      computing foo
      foo
      bar
      

      foo 具有静态属性的好处,包括与类型而非特定实例的关联以及无法被子类覆盖。但是,bar 更进一步,确保该属性只计算一次。

      【讨论】:

        【解决方案3】:

        你的sn-p相当于一个get-only属性,基本上是一样的:

        private static var dateFormatter: NSDateFormatter {
            get {
                print("here here")
                let formatter = NSDateFormatter()
                formatter.dateFormat = "EEEE h a"
                return formatter
            }
        }
        

        如果您只希望它运行一次,您应该像定义惰性属性一样定义它:

        private static var dateFormatter: NSDateFormatter = {
            print("here here")
            let formatter = NSDateFormatter()
            formatter.dateFormat = "EEEE h a"
            return formatter
        }()
        

        【讨论】:

        • 你的意思是私有惰性 var dateFormatter: NSDateFormatter ?
        • 可能值得注意的是,如果原始计算属性位于 协议扩展 上,则上述方法将不起作用,因为赋值使其成为存储属性,您可以' t 将属性存储在协议或其扩展上。您需要将其存储在其他地方(例如,作为具体类型扩展的静态变量等)。
        【解决方案4】:

        您的静态变量不是单例,它只是一个创建并返回日期格式化程序实例的类方法。

        查看这些关于如何创建真正的 sungleton 的答案:Using a dispatch_once singleton model in Swift

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-02-03
          • 1970-01-01
          • 2013-11-12
          相关资源
          最近更新 更多