【问题标题】:Why doesn't didSet work?为什么 didSet 不起作用?
【发布时间】:2016-01-30 01:22:19
【问题描述】:

在我看到的许多didSet 示例中,此代码将返回0,但是,我无法让它返回原始值以外的任何内容。我做错了什么?

斯威夫特

struct Circle {
    var radius: Double {
        didSet {
            if radius < 0 {
                radius = 0
            }
        }
    }
}

var circ = Circle(radius: -25)

print(circ.radius)

输出

-25

【问题讨论】:

    标签: swift swift-structs


    【解决方案1】:

    didSet 在初始化期间不会被调用,只会在之后调用。如果您想在初始化期间验证数据,您的初始化程序应该这样做。

    如果你添加:

    circ.radius = -50
    print(circ.radius)
    

    您会看到它按预期工作,输出将是0.0

    【讨论】:

      【解决方案2】:

      如果您将 didSet 放入 defer 语句中,则可以确保 init 中的 didSet。也适用于deinit

      class Circle {
          var radius: Double {
             didSet {
                if radius < 0 {
                   radius = 0
                }
             }
          }
      
          init(radius: Double) {
              defer { self.radius = radius }
          }
      }
      

      【讨论】:

        【解决方案3】:

        正如 Paul 在 cmets 中所写,属性观察器 didSetwillSet 在值初始化期间不会被调用。

        如果您还想在初始化时调用它们以获得值,您可以添加一个函数调用以在初始化器中初始设置 radius 属性后重新设置它:

        struct Circle {
            var radius: Double {
                didSet {
                    if radius < 0 {
                        radius = 0
                    }
                }
            }
        
            init(radius: Double) {
                self.radius = radius
                setRadius(radius) // <-- this will invoke didSet
            }
        
            mutating func setRadius(radius: Double) {
                self.radius = radius
            }
        }
        
        var circ = Circle(radius: -25)
        
        print(circ.radius) // 0.0
        

        【讨论】:

        • 只是好奇,当setRadius中的第二个声明相同时,除了实际触发didSet之外,为什么我们还需要init中的第一个self.radius = radius
        • 尝试删除它,您将收到一个非常明显的错误提示:“'self' 在所有存储的属性初始化之前使用”。尝试访问 (mutating) 函数 setRadius(radius:) 等同于尝试使用 self,在 self 完全初始化之前不允许这样做。
        【解决方案4】:

        你也可以使用lazy和init(radius ....

        struct Circle {
            lazy var radius: Double = 0.0 {
                didSet {
                    print("didSet called")
                    if radius < 0 {
                        radius = 0
                    }
                }
            }
            init(radius:Double) {
                self.radius = radius
            }
        }
        

        【讨论】:

        • 与上面的其他建议相比,这最适合我的用例。只是想知道,为什么没有懒惰这行不通?
        【解决方案5】:

        为此使用初始化:

        struct Circle {
            var radius: Double
        
            init(radius: Double) {
                self.radius = radius < 0 ? 0 : radius
            }
        }
        
        var circ = Circle(radius: -25)
        
        print(circ.radius)
        
        0.0
        

        【讨论】:

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