在Swift中,重置didSet中的属性是否会触发另一个didSet?

问题描述 投票:0回答:4

我正在对此进行测试,如果您更改

didSet
内的值,您将不会再收到对
didSet
的调用。

var x: Int = 0 {
    didSet {
        if x == 9 { x = 10 }
    }
}

我可以信赖这个吗?它记录在某处吗?我在 Swift 编程语言 文档中没有看到它。

swift swift3 didset property-observer
4个回答
20
投票

来自苹果文档(强调我的):

类似地,如果你实现一个 didSet 观察者,它会传递一个常量 包含旧属性值的参数。您可以命名 参数或使用默认参数名称oldValue。 如果你 为它自己的 didSet 观察者中的属性赋值,新的 您分配的值将替换刚刚设置的值

所以,在didSet中赋值就正式OK了,不会触发无限递归。


18
投票

我还认为,这是不可能的(也许 Swift 2 中没有),但我测试了它并发现了 一个例子,Apple 使用了这个。 (在“查询和设置类型属性”)

struct AudioChannel {
    static let thresholdLevel = 10
    static var maxInputLevelForAllChannels = 0
    var currentLevel: Int = 0 {
        didSet {
            if currentLevel > AudioChannel.thresholdLevel {
                // cap the new audio level to the threshold level
                currentLevel = AudioChannel.thresholdLevel
            }
            if currentLevel > AudioChannel.maxInputLevelForAllChannels {
                // store this as the new overall maximum input level
                AudioChannel.maxInputLevelForAllChannels = currentLevel
            }
        }
    }
}

在这段代码下面,有以下注释:

在这两项检查中的第一项中,didSet 观察者将 currentLevel 设置为不同的值。 这不会,但是,导致观察者被再次调用


1
投票

它会工作得很好,但从 API 使用者的角度来看,这似乎是一个非常糟糕的主意。

它不会像我怀疑的那样递归,所以这至少很好。

我可以想到在少数情况下,设置者更改我的设置是可以接受的。一个这样的示例可能是设置为角度的变量,该角度会自动标准化为

[0, 2π]


0
投票

在 Swift5, 2024 中,没有递归。

var dogs: [Dog] = [] {
    didSet {
        print("sorting")
        dogs.sort{
            $0.cat.caseInsensitiveCompare($1.cat) == .orderedAscending
        }
    }
}

它只运行一次。

var dogs: [Dog] = [] {
    didSet {
        print("assigning")
        dogs = []
    }
}

它只运行一次。

已测试!

© www.soinside.com 2019 - 2024. All rights reserved.