【问题标题】:Swift Programming: getter/setter in stored propertySwift 编程:存储属性中的 getter/setter
【发布时间】:2014-07-29 15:59:01
【问题描述】:

如何在 Swift 中覆盖存储属性的设置器?

在 Obj-C 中,我可以覆盖它的 setter,但 Swift 似乎对将 getter/setter 用于存储属性并不满意。

假设我有一个 Card 类,其属性名为 rank。我不希望客户端给它任何无效值,因此,在 Objective-C 中,我可以覆盖 setRank 以便它执行额外的检查。但是 Swift 中的 willSet 似乎没有帮助,因为 newValue 是常量,分配 rank 没有意义,因为 setter 将在循环中被调用。

【问题讨论】:

  • 您找到了这样做的方法吗?我自己也需要这种功能……
  • 我找到了。看看我的回答...
  • didGet 或模拟怎么样?

标签: ios swift


【解决方案1】:

好的。阅读有关 Swift 的 Apple 文档,我发现 this:

如果你在它自己的 didSet 观察者中为一个属性赋值, 您分配的新值将替换刚刚设置的值。

所以你所要做的就是:

var rank: Int = 0 {
    didSet {
        // Say 1000 is not good for you and 999 is the maximum you want to be stored there
        if rank >= 1000  {
            rank = 999
        }
    }
}

【讨论】:

  • didGet 或模拟怎么样?
  • 不确定我是否理解您的问题。能说的具体点吗?
  • 我需要在获取之前调用一些代码。我能够在 obj-c 中执行此操作,但我看不到如何在 Swift 中执行此操作。我唯一看到的是使用两个属性:一个是公共的,一个是私有的,公共调用我的代码并返回私有属性的值。这就是我询问 didGet 的原因
  • 计算属性只能有一个 getter。例如var rankTimesTwo: Int { get { return rank * 2 } }
  • 像魅力一样工作!注意在 init() 中设置属性时不会调用它
【解决方案2】:

您不能为存储的属性覆盖get/set,但可以使用属性观察器willSet/didSet

var totalSteps: Int = 0 {
    willSet(newTotalSteps) {
        println("About to set totalSteps to \(newTotalSteps)")
    }
    didSet {
        if totalSteps > oldValue  {
            println("Added \(totalSteps - oldValue) steps")
        }
    }
}

willSet 的默认参数名称为 newValuedidSet 的默认参数名称为 oldValue,或者您可以像 willSet(newTotalSteps) 一样自行命名。

【讨论】:

  • 这行得通。但并没有解决我的问题,也许我最初的问题不够清楚。
  • 假设我有一个Card 类,其属性名为rank。我不希望客户端给它任何值,因此,在 Objective-C 中,我可以覆盖 setRank 以便它执行额外的检查。但是 Swift 中的 willSet 似乎没有帮助,因为 newValue 是常量,分配 rank 没有意义,因为 setter 将在循环中调用。
  • 我不完全确定您的意思,但您不能在设置后使用didSet 检查rank,如果验证失败,请将其重置为其他内容,例如oldValue?
【解决方案3】:

get 和 set 用于计算属性(它们没有任何后备存储)。 (在我看来,关键字'var'在这里令人困惑)

  • 为实例变量调用 willSet 和 didSet(使用 didSet 覆盖任何更改)
  • set 和 get 纯粹用于计算属性

【讨论】:

    【解决方案4】:

    如果你不想使用didSet,它有属性值暂时错误的问题,你应该在它周围包裹一个计算属性。

    private var _foo:Int = 0
    var foo:Int {
        get {
            return _foo
        }
        set {
            if(newValue > 999) {
                _foo = 999
            } else {
                _foo = newValue
            }
        }
    }
    

    或者:

    private var _foo:Int = 0
    var foo:Int {
        get {
            return _foo
        }
        set {
            guard newValue <= 999 else {
                _foo = 999
                return
            }
            _foo = newValue
        }
    }
    

    【讨论】:

    • 使用两个变量没有意义。
    • 这仅使用一个属性(变量):foo 只是_foo 的计算表达式,不要让“var”关键字欺骗您!这确实意味着可以从私有命名空间访问两个条目,但这与受保护/公共无关,并且始终保持 foo 的值有效。这本质上是“视图”模式。您通过didSet 重写 遇到的问题,除了它有一段时间无效之外,还有一个无限循环的巨大可能性,因为您从内部重新进入didSet 处理程序didSet.
    【解决方案5】:

    简化示例:

    class Shape {
        var sideLength: Double {
        get {
            return self.sideLength
        }
        set {
            // Implement the setter here.
            self.sideLength = newValue
        }
        }
    }
    

    完整示例

    查看此示例中的perimeter

    摘自:Apple Inc.“Swift 编程语言”。电子书。 https://itun.es/us/jEUH0.l

    class EquilateralTriangle: NamedShape {
        var sideLength: Double = 0.0
    
        init(sideLength: Double, name: String) {
            self.sideLength = sideLength
            super.init(name: name)
            numberOfSides = 3
        }
    
        var perimeter: Double {
        get {
            return 3.0 * sideLength
        }
        set {
            sideLength = newValue / 3.0
        }
        }
    
        override func simpleDescription() -> String {
            return "An equilateral triagle with sides of length \(sideLength)."
        }
    }
    var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
    triangle.perimeter
    triangle.perimeter = 9.9
    triangle.sideLength”
    

    【讨论】:

    • 在这种情况下,perimeter 仍然是一个计算属性。如何在不引入计算属性的情况下覆盖 sideLength?
    • @bohanl 我添加了一个使用getset 的简化示例
    • 您的“完整示例”显示的是计算属性,而不是存储属性,并且您的“简化示例”不起作用。
    • 我的立场是正确的。就好像 Objective-C 中 @property(auto-synthesized getters+setters) 的抽象在 Swift 中没有被抽象。讽刺的是……
    • 您的“简化示例”是在自身的吸气剂中调用吸气剂。 Inf 循环...崩溃。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-25
    • 2015-08-05
    • 2012-09-09
    • 1970-01-01
    • 2018-11-08
    • 1970-01-01
    相关资源
    最近更新 更多