物业获取者和二传手

时间:2014-06-03 21:35:37

标签: swift properties compiler-warnings getter-setter

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

  

尝试在自己的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
        }
    }
    // ...
}

12 个答案:

答案 0 :(得分:213)

Setters和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

答案 1 :(得分:101)

Swift中的Setters / getters与ObjC完全不同。该属性成为计算属性,这意味着具有支持变量,如_x,就像在ObjC中一样。

在下面的解决方案代码中,您可以看到xTimesTwo 存储任何内容,只需计算 x的结果。

请参阅Official docs on computed properties

您想要的功能也可能是Property Observers

您需要的是:

var x:Int

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

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

答案 2 :(得分:93)

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

class Point {

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

至于吸气剂......

class Point {

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

答案 3 :(得分:30)

详细说明GoZoner的答案:

你真正的问题是你递归地打电话给你的吸气鬼。

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

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

答案 4 :(得分:17)

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

var temX : Int? 
var x: Int?{

    set(newX){
       temX = newX
    }

    get{
        return temX
    }
}

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

我们可以像这样调用setter

x = 10

在给定的代码行

下触发将调用Getter
var newVar = x

答案 5 :(得分:8)

递归使用x定义x。好像有人问你你多大了?你回答“我是我的两倍”。这没有意义。

你必须说我是John年龄的两倍或任何其他变量你自己。

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

拇指规则是从不中获取属性本身 getter即get。因为这会触发另一个get,这会引发另一个struct Person{ var name: String{ get{ print(name) // DON'T do this!!!! return "as" } set{ } } } let p1 = Person() 。 。 。甚至不打印。因为打印还需要在打印之前“获取”值!

didSet

因为这会发出以下警告:

  

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

错误看起来很模糊:

enter image description here

作为替代方案,您可能希望使用didSet。使用$sAttributeName = 'brands'; $mOptionValueId = 250; // 250 is Id of Brand 1 $newOptionValueId = 255; // 255 is Id of Brand 2 $productsCollection = Mage::getModel('catalog/product')->getCollection() ->addAttributeToSelect('*') ->addFieldToFilter( $sAttributeName, array( 'eq' => $mOptionValueId ) ); $storeId = Mage::app()->getStore()->getStoreId(); foreach($productsCollection as $product) { $productId = $product->getId(); Mage::getSingleton('catalog/product_action')->updateAttributes( array($productId), array('brands' => $newOptionValueId), $storeId ); } ,您将获得之前设置的值并保持设置的值。有关详情,请参阅this answer

答案 6 :(得分: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
        }
   }

创建对象

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

吸气剂

print(triangle.perimeter) // invoking getter

设置器

triangle.perimeter = 9.9 // invoking setter

答案 7 :(得分:6)

尝试使用:

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!,所以我所做的只是使它成为可选类型。

答案 8 :(得分:0)

Swift中的setter和getter适用于计算属性/变量。这些属性/变量实际上并不存储在内存中,而是基于存储的属性/变量的值来计算。

请参阅Apple关于此主题的Swift文档:Swift Variable Declarations

答案 9 :(得分:0)

这是一个理论上的答案。可以找到here

  

{get set}属性不能是常量存储的属性。它应该是一个计算属性,应该同时实现get和set。

答案 10 :(得分:0)

针对Swift 5.1的更新

从Swift 5.1开始,您现在无需使用 get 关键字即可获取变量。例如:

var helloWorld: String {
"Hello World"
}

答案 11 :(得分:0)

我不知道这是否是一个好习惯,但是您可以执行以下操作:

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