快速编程: 存储属性中的 getter/setter

如何在 Swift 中覆盖存储属性的 setter?

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

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

60261 次浏览

Simplified Example:

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

Full example

Check out perimeter in this example.

Excerpt From: Apple Inc. “The Swift Programming Language.” iBooks. 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”

You can't override get/set for a stored property but you can use property observers willSet/didSet:

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

The default parameter names are newValue for willSet and oldValue for didSet, or you can name them yourself as in willSet(newTotalSteps).

Ok. Reading through Apples documentation on Swift I found this:

If you assign a value to a property within its own didSet observer, the new value that you assign will replace the one that was just set.

So all you have to do is this:

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
}
}
}

get and set are for computed properties (they don't have any backing store). (In my opinion, the keyword 'var' is confusing here)

  • willSet and didSet are called for an instance variable (Use didSet to override any changes)
  • set and get are purely for computed properties

If you don't want to use didSet, which has the problem that the property's value is temporarily wrong, you should wrap a computed property around it.

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

Or:

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