通过这个简单的类,我得到了编译器警告

试图在自己的setter/getter中修改/访问x

当我这样使用它时:

var p: point = Point()
p.x = 12

我得到一个EXC_BAD_ACCESS。我怎么能做到这一点没有显式支持变量?

class Point {

    var x: Int {
        set {
            x = newValue * 2 //Error
        }
        get {
            return x / 2 //Error
        }
    }
    // ...
}

当前回答

更新:Swift 4

在下面的类setter和getter应用于变量sideLength

class Triangle: {
    var sideLength: Double = 0.0

    init(sideLength: Double, name: String) { //initializer method
        self.sideLength = sideLength
        super.init(name: name)
        numberOfSides = 3
    }

    var perimeter: Double {
        get { // getter
            return 3.0 * sideLength
        }
        set(newValue) { //setter
            sideLength = newValue / 4.0
        }
   }

创建对象

var triangle = Triangle(sideLength: 3.9, name: "a triangle")

Getter

print(triangle.perimeter) // invoking getter

triangle.perimeter = 9.9 // invoking setter

其他回答

setter和getter应用于计算属性;这样的属性在实例中没有存储空间——getter中的值将从其他实例属性中计算出来。在你的例子中,没有x被赋值。

显式地:“在没有显式支持ivars的情况下如何做到这一点”。您不能这样做—您需要备份计算的属性。试试这个:

class Point {
  private var _x: Int = 0             // _x -> backingX
  var x: Int {
    set { _x = 2 * newValue }
    get { return _x / 2 }
  }
}

具体来说,在Swift REPL中:

 15> var pt = Point()
pt: Point = {
  _x = 0
}
 16> pt.x = 10
 17> pt
$R3: Point = {
  _x = 20
}
 18> pt.x
$R4: Int = 10

更新:Swift 4

在下面的类setter和getter应用于变量sideLength

class Triangle: {
    var sideLength: Double = 0.0

    init(sideLength: Double, name: String) { //initializer method
        self.sideLength = sideLength
        super.init(name: name)
        numberOfSides = 3
    }

    var perimeter: Double {
        get { // getter
            return 3.0 * sideLength
        }
        set(newValue) { //setter
            sideLength = newValue / 4.0
        }
   }

创建对象

var triangle = Triangle(sideLength: 3.9, name: "a triangle")

Getter

print(triangle.perimeter) // invoking getter

triangle.perimeter = 9.9 // invoking setter

我不知道这是不是一个好的练习,但是你可以这样做:

class test_ancestor {
    var prop: Int = 0
}


class test: test_ancestor {
    override var prop: Int {
        get {
            return super.prop // reaching ancestor prop
        }
        set {
            super.prop = newValue * 2
        }
    }
}

var test_instance = test()
test_instance.prop = 10

print(test_instance.prop) // 20

阅读更多

详细解释一下GoZoner的回答:

这里真正的问题是递归地调用getter。

var x:Int
    {
        set
        {
            x = newValue * 2 // This isn't a problem
        }
        get {
            return x / 2 // Here is your real issue, you are recursively calling 
                         // your x property's getter
        }
    }

就像上面的代码注释建议的那样,你无限地调用x属性的getter,它将继续执行,直到你得到一个EXC_BAD_ACCESS代码(你可以在你的Xcode的游乐场环境的右下角看到旋转器)。

请看Swift文档中的例子:

struct Point {
    var x = 0.0, y = 0.0
}
struct Size {
    var width = 0.0, height = 0.0
}
struct AlternativeRect {
    var origin = Point()
    var size = Size()
    var center: Point {
        get {
            let centerX = origin.x + (size.width / 2)
            let centerY = origin.y + (size.height / 2)
            return Point(x: centerX, y: centerY)
        }
        set {
            origin.x = newValue.x - (size.width / 2)
            origin.y = newValue.y - (size.height / 2)
        }
    }
}

注意,center computed属性在变量的声明中从不修改或返回自身。

您可以使用属性观察者自定义设置值。要做到这一点,使用'didSet'而不是'set'。

class Point {

var x: Int {
    didSet {
        x = x * 2
    }
}
...

至于getter…

class Point {

var doubleX: Int {
    get {
        return x / 2
    }
}
...