Swift编程:存储属性中的getter / setter


102

如何覆盖Swift中存储属性的设置器?

在Obj-C中,我可以覆盖它的setter,但是Swift对于将getter / setter用于存储属性似乎并不满意。

假设我有一Card堂课,其属性称为rank。我不希望客户端给它任何无效的值,因此,在Objective-C中,我可以覆盖setRank它,以便它执行附加检查。但是willSet在Swift中似乎并没有帮助,因为newValue它是常量,并且分配没有意义,rank因为setter将在循环中调用。


您找到了一种方法吗?我自己需要这种功能...
Mihai Fratu 2014年

我找到了。看看我的答案...
Mihai Fratu 2014年

那didGet或类似物呢?
fnc12

Answers:


107

好。通过阅读有关Swift的Apple文档,我发现了这一点

如果您在其自己的didSet观察器中为属性分配值,则您分配的新值将替换刚设置的值。

因此,您要做的就是:

var rank: Int = 0 {
    didSet {
        // Say 1000 is not good for you and 999 is the maximum you want to be stored there
        if rank >= 1000  {
            rank = 999
        }
    }
}

那didGet或类似物呢?
fnc12

不确定我是否理解您的问题。请您更具体吗?
Mihai Fratu 2015年

我需要在获取之前调用一些代码。我能够在obj-c中执行此操作,但看不到如何在Swift中执行此操作。我唯一看到的是使用两个属性:一个是public,一个是private,public调用我的代码并返回private属性的值。这就是为什么我询问didGet
fnc12

您只能为计算属性使用一个吸气剂。例如var rankTimesTwo: Int { get { return rank * 2 } }
Mihai Fratu 2015年

2
奇迹般有效!当心设定的init()的属性时,它不会被称为
克里斯托夫

35

您不能为存储的属性覆盖get/ set,但是可以使用属性观察者willSet/ didSet

var totalSteps: Int = 0 {
    willSet(newTotalSteps) {
        println("About to set totalSteps to \(newTotalSteps)")
    }
    didSet {
        if totalSteps > oldValue  {
            println("Added \(totalSteps - oldValue) steps")
        }
    }
}

默认参数名称是newValuefor willSetoldValuefor didSet,或者您也可以像中一样自行命名willSet(newTotalSteps)


这可行。但是并不能解决我的问题,也许我对最初的问题还不够清楚。
bohanl 2014年

假设我有一Card堂课,其属性称为rank。我不希望客户端给它任何值,因此,在Objective-C中,我可以覆盖setRank它,以便它执行附加检查。但是willSet在Swift中似乎并没有帮助,因为newValue它是常量,并且分配没有意义,rank因为setter将在循环中调用。
bohanl 2014年

2
我不完全确定您的意思,但是您无法在设置后didSet检查rank它,如果验证失败,请将其重置为其他内容,例如oldValue
约瑟夫·马克

9

get和set用于计算的属性(它们没有任何后备存储)。(我认为关键字“ var”在这里令人困惑)

  • 将为实例变量调用willSet和didSet(使用didSet覆盖所有更改)
  • 设置和获取纯粹用于计算属性

9

如果您不想使用didSet,这会带来该属性的值暂时错误的问题,则应在其周围包装一个已计算的属性。

private var _foo:Int = 0
var foo:Int {
    get {
        return _foo
    }
    set {
        if(newValue > 999) {
            _foo = 999
        } else {
            _foo = newValue
        }
    }
}

要么:

private var _foo:Int = 0
var foo:Int {
    get {
        return _foo
    }
    set {
        guard newValue <= 999 else {
            _foo = 999
            return
        }
        _foo = newValue
    }
}

使用两个变量没有任何意义。
Piyush

1
这仅使用一个属性(变量):foo只是的计算表达式_foo,请勿让“ var”关键字欺骗您!这确实意味着可以从私有名称空间访问两个条目,但是它们与受保护的/公共的无关,并且始终保持foo有效值。这本质上是“视图”模式。除了具有一段时间的无效时间外,通过via 进行重写遇到的问题还didSet在于,由于didSet要从内部重新输入处理程序,因此存在无限循环的巨大潜力didSet
吉姆·德里斯科尔

-8

简化示例:

class Shape {
    var sideLength: Double {
    get {
        return self.sideLength
    }
    set {
        // Implement the setter here.
        self.sideLength = newValue
    }
    }
}

完整的例子

perimeter在此示例中查看。

摘录自:苹果公司“ The Swift Programming Language”。iBooks。https://itun.es/us/jEUH0.l

class EquilateralTriangle: NamedShape {
    var sideLength: Double = 0.0

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

    var perimeter: Double {
    get {
        return 3.0 * sideLength
    }
    set {
        sideLength = newValue / 3.0
    }
    }

    override func simpleDescription() -> String {
        return "An equilateral triagle with sides of length \(sideLength)."
    }
}
var triangle = EquilateralTriangle(sideLength: 3.1, name: "a triangle")
triangle.perimeter
triangle.perimeter = 9.9
triangle.sideLength”

3
在这种情况下,perimeter仍然是计算属性。如何在不引入计算属性的情况下覆盖sideLength?
bohanl 2014年

@bohanl我使用get和添加了一个简化示例set
Mike Rapadas 2014年

6
您的“完整示例”显示的是计算属性,而不是存储属性,而“简化示例”不起作用。
Caleb

我站得住了。好像在Objective-C中@property(自动合成的getters + setters)的抽象在Swift中并没有一样。具有讽刺意味的是…
Mike Rapadas 2014年

6
您的“简化示例”是在自身的getter中调用getter。Inf循环...崩溃。
jakenberg
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.