有了这个简单的类,我得到编译器警告
试图
x
在自己的setter/getter中修改/访问
当我像这样使用它时:
var p: point = Point() p.x = 12
我得到一个EXC_BAD_ACCESS.如果没有明确支持ivars,我怎么能这样做?
class Point { var x: Int { set { x = newValue * 2 //Error } get { return x / 2 //Error } } // ... }
GoZoner.. 220
塞特犬和吸气者适用于computed properties
; 这样的属性在实例中没有存储 - 来自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
Jack.. 104
Swift中的Setter/getters与ObjC完全不同.该属性变成了计算的属性,这意味着它不具有背衬变量如_x
因为它会在ObjC.
在上述方案中的代码下面你可以看到xTimesTwo
并没有存储任何东西,而是简单地计算从结果x
.
请参阅有关计算属性的官方文档.
您想要的功能也可能是Property Observers.
你需要的是:
var x: Int var xTimesTwo: Int { set { x = newValue / 2 } get { return x * 2 } }
您可以修改setter/getters中的其他属性,这就是它们的用途.
塞特犬和吸气者适用于computed properties
; 这样的属性在实例中没有存储 - 来自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
你是递归定义x
的x
.好像有人问你你多大了?你回答"我是我的两倍".这没有意义.
你必须说我是约翰的年龄或任何其他变量,但你自己.
计算变量总是依赖于另一个变量.
拇指法则是永远不会从访问属性本身内的吸气剂,即get
.因为这会触发另一个get
会触发另一个...甚至不打印.因为打印还需要在打印之前"获取"该值!
struct Person{ var name: String{ get{ print(name) // DON'T do this!!!! return "as" } set{ } } } let p1 = Person()
因为这会发出以下警告:
试图从它自己的getter中访问'name'.
该错误看起来像这样模糊:
作为替代方案,您可能想要使用didSet
.随着didSet
你将保持之前设置的值,并设置为.欲了解更多看到这个答案.
试试这个:
var x:Int! var xTimesTwo:Int { get { return x * 2 } set { x = newValue / 2 } }
这基本上就是Jack Wu的答案,但不同的是,在Jack Wu的回答中,他的x变量是var x: Int
,在我的中,我的x变量是这样的:var x: Int!
所以我所做的只是让它成为一个可选类型.
详细说明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) } } }
注意中心计算属性永远不会在变量的声明中修改或返回自身.
为了覆盖setter
和getter
快速变量,使用下面给出的代码
var temX : Int? var x: Int?{ set(newX){ temX = newX } get{ return temX } }
我们需要将变量的值保存在临时变量中,因为尝试访问其getter/setter被覆盖的同一变量将导致无限循环.
我们可以像这样调用setter
x = 10
在给定的代码行下面将触发Getter
var newVar = x
Swift中的Setter/getters与ObjC完全不同.该属性变成了计算的属性,这意味着它不具有背衬变量如_x
因为它会在ObjC.
在上述方案中的代码下面你可以看到xTimesTwo
并没有存储任何东西,而是简单地计算从结果x
.
请参阅有关计算属性的官方文档.
您想要的功能也可能是Property Observers.
你需要的是:
var x: Int var xTimesTwo: Int { set { x = newValue / 2 } get { return x * 2 } }
您可以修改setter/getters中的其他属性,这就是它们的用途.
在下面的类中,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 { //setter sideLength = newValue / 4.0 } }
var triangle = Triangle(sideLength: 3.9, name: "a triangle")
print(triangle.perimeter) // invoking getter
triangle.perimeter = 9.9 // invoking setter
您可以使用属性观察器自定义设置值.要做到这一点,请使用'didSet'而不是'set'.
class Point { var x: Int { didSet { x = x * 2 } } ...
至于吸气...
class Point { var doubleX: Int { get { return x / 2 } } ...