物业获取者和二传手

Ato*_*mix 179 properties compiler-warnings getter-setter swift

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

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

当我像这样使用它时:

var p: point = Point()
p.x = 12
Run Code Online (Sandbox Code Playgroud)

我得到一个EXC_BAD_ACCESS.如果没有明确支持ivars,我怎么能这样做?

class Point {

    var x: Int {
        set {
            x = newValue * 2 //Error
        }
        get {
            return x / 2 //Error
        }
    }
    // ...
}
Run Code Online (Sandbox Code Playgroud)

GoZ*_*ner 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 }
  }
}
Run Code Online (Sandbox Code Playgroud)

具体来说,在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
Run Code Online (Sandbox Code Playgroud)


Jac*_*ack 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
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以修改setter/getters中的其他属性,这就是它们的用途.

  • 您可以使用`didSet`,它允许您在设置后立即更改值.没有什么可以获得... (5认同)
  • 注意:如果您想恢复该值,因为它是无效输入,您需要在“didSet”中将“x”设置回“oldValue”。来自 Objective-C 属性的这种行为变化非常令人困惑,谢谢! (3认同)

cSq*_*rel 100

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

class Point {

var x: Int {
    didSet {
        x = x * 2
    }
}
...
Run Code Online (Sandbox Code Playgroud)

至于吸气...

class Point {

var doubleX: Int {
    get {
        return x / 2
    }
}
...
Run Code Online (Sandbox Code Playgroud)

  • 我看到的是:`var x:Int = 0 {didSet {...`。 (2认同)

Abd*_*hsh 31

详细说明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
        }
    }
Run Code Online (Sandbox Code Playgroud)

就像上面的代码注释所示,你无限地调用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)
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

注意中心计算属性永远不会在变量的声明中修改或返回自身.

  • 指出递归的优秀注意事项. (3认同)

Seb*_*Roy 18

为了覆盖settergetter快速变量,使用下面给出的代码

var temX : Int? 
var x: Int?{

    set(newX){
       temX = newX
    }

    get{
        return temX
    }
}
Run Code Online (Sandbox Code Playgroud)

我们需要将变量的值保存在临时变量中,因为尝试访问其getter/setter被覆盖的同一变量将导致无限循环.

我们可以像这样调用setter

x = 10
Run Code Online (Sandbox Code Playgroud)

在给定的代码行下面将触发Getter

var newVar = x
Run Code Online (Sandbox Code Playgroud)


Hon*_*ney 8

你是递归定义xx.好像有人问你你多大了?你回答"我是我的两倍".这没有意义.

你必须说我是约翰的年龄或任何其他变量,你自己.

计算变量总是依赖于另一个变量.


拇指法则是永远不会从访问属性本身的吸气剂,即get.因为这会触发另一个get会触发另一个...甚至不打印.因为打印还需要在打印之前"获取"该值!

struct Person{
    var name: String{
        get{
            print(name) // DON'T do this!!!!
            return "as"
        }
        set{
        }
    }
}

let p1 = Person()
Run Code Online (Sandbox Code Playgroud)

因为这会发出以下警告:

试图从它自己的getter中访问'name'.

该错误看起来像这样模糊:

在此输入图像描述

作为替代方案,您可能想要使用didSet.随着didSet你将保持之前设置的值,并设置为.欲了解更多看到这个答案.


Sar*_*ith 7

更新: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 { //setter
            sideLength = newValue / 4.0
        }
   }
Run Code Online (Sandbox Code Playgroud)

创建对象

var triangle = Triangle(sideLength: 3.9, name: "a triangle")
Run Code Online (Sandbox Code Playgroud)

消气

print(triangle.perimeter) // invoking getter
Run Code Online (Sandbox Code Playgroud)

二传手

triangle.perimeter = 9.9 // invoking setter
Run Code Online (Sandbox Code Playgroud)


Epi*_*ter 6

试试这个:

var x:Int!

var xTimesTwo:Int {
    get {
        return x * 2
    }
    set {
        x = newValue / 2
    }
}
Run Code Online (Sandbox Code Playgroud)

这基本上就是Jack Wu的答案,但不同的是,在Jack Wu的回答中,他的x变量是var x: Int,在我的中,我的x变量是这样的:var x: Int!所以我所做的只是让它成为一个可选类型.