如何在Swift中设置属性值,而不在初始化上下文之外调用其didSet()
函数?以下代码是在类noside()
函数
class Test
{
var toggle : Bool = 0
var hoodwink : Int = 0 {
didSet(hoodwink)
{
toggle = !toggle
}
}
// failed attempt to set without a side effect
func noside(newValue : Int)
{
hoodwink = newValue
println("hoodwink: \(hoodwink) state: \(toggle)")
}
func withside(newValue : Int)
{
self.hoodwink = newValue
println("hoodwink: \(hoodwink) state: \(toggle)")
}
}
使用自动合成属性在Objective-C中进行操作非常简单:
有副作用(如果存在于二传手中):
self.hoodwink = newValue;
没有副作用:
_hoodwink = newValue;
答案 0 :(得分:8)
可能存在的问题是提供一个绕过你的didSet
的setter var dontTriggerObservers:Bool = false
var selectedIndexPath:NSIndexPath? {
didSet {
if(dontTriggerObservers == false){
//blah blah things to do
}
}
}
var primitiveSetSelectedIndexPath:NSIndexPath? {
didSet(indexPath) {
dontTriggerObservers = true
selectedIndexPath = indexPath
dontTriggerObservers = false
}
}
丑陋但可行
答案 1 :(得分:7)
你在Objective-C中做什么来“避免副作用”是访问属性的后备存储 - 它的实例变量,默认情况下以下划线为前缀(你可以使用@synthesize
指令更改它)
然而,看起来Swift语言设计师特别注意使得无法访问属性的支持变量:根据该书,
如果您有使用Objective-C的经验,您可能知道它提供了两种方法来存储值和引用作为类实例的一部分。除了属性之外,您还可以使用实例变量作为存储在属性中的值的后备存储。
Swift将这些概念统一到一个属性声明中。 Swift属性没有相应的实例变量,并且不会直接访问属性的后备存储。 (重点是我的)
当然,这仅适用于使用“常规语言”的意思,而不是使用反射:它可能会以牺牲可读性为代价来解决这一限制。
答案 2 :(得分:0)
如果您确切知道何时应用副作用,请明确说明:
1解决方案:
func noside(newValue : Int) {
hoodwink = newValue
}
func withside(newValue : Int) {
self.hoodwink = newValue
toggle = !toggle
}
2解决方案:
var toggle : Bool = false
var hoodwink : Int = 0
var hoodwinkToggle: Int {
get { return hoodwink }
set(newValue) {
hoodwink = newValue
toggle = !toggle
}
}
我认为这些解决方案将更加清晰和可读,然后使用一个变量,在某些调用中应该有副作用,而不应该在其他变量。
答案 3 :(得分:0)
我试图解决的问题是,我希望在一个值发生变化时进行doCommonUpdate
调用,或者如果两个值同时更改则进行调用。这样做会创建一个递归,因为如果其中一个值发生更改,则每次都会调用didSet
。示例设置,我的更多参与:
class Person {
var first: String = "" {
didSet {
updateValues(first: first, last: last)
}
}
var last: String = "" {
didSet {
updateValues(first: first, last: last)
}
}
init() {}
init(first: String, last: String) {
self.first = first
self.last = last
}
// also want to set both at the same time.
func updateValues(first: String, last: String) {
// self.first = first // causes recursion.
// self.last = last
doCommonSetup(first: first, last: last)
}
func doCommonSetup(first: String, last: String) {
print(first, last)
}
}
let l = Person()
l.first = "Betty"
l.last = "Rubble"
_ = Person(first: "Wilma", last: "Flintstone")
> Betty
> Betty Rubble
注意由于注释掉的行,Wilma不会打印。
我的解决方案是将所有这些变量移动到一个单独的结构中。这种方法解决了这个问题,并且具有创建另一个有助于意义的分组的附带好处。当任一值独立变化以及同时更改两个值时,我们仍会得到doCommonSetup
。
class Person2 {
struct Name {
let first: String
let last: String
}
var name: Name
init() {
name = Name(first: "", last: "")
}
init(first: String, last: String) {
name = Name(first: first, last: last)
updateValues(name: name)
}
var first: String = "" {
didSet {
name = Name(first: first, last: self.last)
updateValues(name: name)
}
}
var last: String = "" {
didSet {
name = Name(first: self.first, last: last)
updateValues(name: name)
}
}
// also want to set both at the same time.
func updateValues(name: Name) {
self.name = name
doCommonSetup(name: name)
}
func doCommonSetup(name: Name) {
print(name.first, name.last)
}
}
let p = Person2()
p.first = "Barney"
p.last = "Rubble"
_ = Person2(first: "Fred", last: "Flintstone")
> Barney
> Barney Rubble
> Fred Flintstone