属性获取器和设置器
Posted
技术标签:
【中文标题】属性获取器和设置器【英文标题】:Property getters and setters 【发布时间】:2014-07-24 09:20:42 【问题描述】:通过这个简单的类,我得到了编译器警告
试图在自己的 setter/getter 中修改/访问
x
当我这样使用它时:
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
// ...
【问题讨论】:
这样做也会给编译器带来额外的负担,并且会大量消耗 CPU。我就是这么做的:| . This 是我创建的错误。 (我正在使用游乐场) 这种行为令人困惑,而不是使用set
你想使用didSet
。当您实现set
时,属性在 Swift 中的行为与 Objective-C 或其他语言不同。请参阅 answer below from @jack 和 example of didSet
from @cSquirrel
【参考方案1】:
我不知道这是否是一种好习惯,但您可以这样做:
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
Read more
【讨论】:
【参考方案2】:更新: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")
吸气剂
print(triangle.perimeter) // invoking getter
二传手
triangle.perimeter = 9.9 // invoking setter
【讨论】:
【参考方案3】:您可以使用属性观察器自定义设置值。为此,请使用 'didSet' 而不是 'set'。
class Point
var x: Int
didSet
x = x * 2
...
至于吸气剂...
class Point
var doubleX: Int
get
return x / 2
...
【讨论】:
你怎么能用这个模式中的默认值初始化x
?
我明白了,应该是:var x: Int = 0 didSet ...
。【参考方案4】:
Swift 中的 Setter/getter 与 ObjC 完全不同。该属性变成了一个计算属性,这意味着它确实没有像在 ObjC 中那样有一个支持变量,例如 _x
。
在下面的解决方案代码中,您可以看到xTimesTwo
确实不 存储任何内容,而只是计算来自x
的结果。
见Official docs on computed properties。
您想要的功能也可能是Property Observers。
你需要的是:
var x: Int
var xTimesTwo: Int
set
x = newValue / 2
get
return x * 2
您可以修改 setter/getter 中的其他属性,这就是它们的用途。
【讨论】:
是的,这就是我在文档中阅读的内容。我跳过了属性部分,似乎没有办法解决这个问题,对吧? 是的,如果你真的想这样做,你将需要另一个实例变量来“支持”第一个。但是,setter 并不是为此目的而设计的,您可能应该重新考虑您要通过此实现的目标。 您可以使用didSet
,它允许您在设置后立即更改该值。没有什么可以得到的......
注意:如果您想恢复该值,因为它是无效输入,您需要在didSet
中将x
设置回oldValue
。来自 Objective-C 属性的这种行为变化非常令人困惑,谢谢!【参考方案5】:
Swift 5.1 更新
从 Swift 5.1 开始,您现在可以在不使用 get 关键字的情况下获取变量。例如:
var helloWorld: String
"Hello World"
【讨论】:
如果我尝试更改,helloWorld = "macWorld",无法赋值:'helloWorld' is a get-only property error is shown. 是否有可能分配新值?还是没有? 我认为不可能。 从字面上看,var helloWorld: String "Hello World" 和 let helloWorld: String = "Hello World" 是一样的吗? 是的,我想是的。【参考方案6】:这是一个理论上的答案。可以找到here
get set 属性不能是常量存储属性。它应该是一个计算属性,并且 get 和 set 都应该实现。
【讨论】:
【参考方案7】:您正在递归地用x
定义x
。好像有人问你几岁?你回答“我的年龄是我的两倍”。这是没有意义的。
你必须说我是约翰的两倍或任何其他变量但你自己。
计算变量总是依赖于另一个变量。
经验法则是从不从 在 getter 即get
中访问属性本身。因为那会触发另一个get
,这会触发另一个. . .甚至不要打印它。因为打印还需要“获取”值才能打印!
struct Person
var name: String
get
print(name) // DON'T do this!!!!
return "as"
set
let p1 = Person()
因为这会给出以下警告:
试图从它自己的 getter 中访问 'name'。
这个错误看起来很模糊:
作为替代方案,您可能想要使用didSet
。使用didSet
,您将保留之前设置的值,然后设置为。更多信息请见this answer。
【讨论】:
【参考方案8】:Setters 和 Getters 申请computed properties
;此类属性在实例中没有存储空间 - 来自 getter 的值旨在从其他实例属性中计算得出。在您的情况下,没有要分配的 x
。
明确地:“没有明确的支持 ivars 我怎么能做到这一点”。你不能 - 你需要 something 来备份计算的属性。试试这个:
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
【讨论】:
【参考方案9】:要覆盖 setter
和 getter
的 swift 变量,请使用以下代码
var temX : Int?
var x: Int?
set(newX)
temX = newX
get
return temX
我们需要将变量的值保存在一个临时变量中,因为尝试访问其 getter/setter 被覆盖的同一个变量将导致无限循环。
我们可以像这样简单地调用setter
x = 10
Getter 将在给定代码行下方触发时调用
var newVar = x
【讨论】:
【参考方案10】:试试这个:
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!
,所以我所做的只是将其设为可选类型。
【讨论】:
【参考方案11】:详细说明 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 的 Playground 环境的右下角看到微调器)。
考虑Swift documentation中的示例:
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)
注意中心计算属性如何在变量声明中从不修改或返回自身。
【讨论】:
经验法则是从不从内部 getter 即get
访问属性本身。因为那会触发另一个 get
,这会触发另一个 . . .甚至不要打印它。因为打印还需要“获取”值才能打印!【参考方案12】:
Swift 中的 Setter 和 getter 适用于计算属性/变量。这些属性/变量实际上并不存储在内存中,而是根据存储的属性/变量的值计算得出的。
请参阅 Apple 关于该主题的 Swift 文档:Swift Variable Declarations。
【讨论】:
以上是关于属性获取器和设置器的主要内容,如果未能解决你的问题,请参考以下文章