【发布时间】:2018-07-23 20:29:41
【问题描述】:
我们在 didSet 中使用循环时遇到了这种奇怪的行为。我们的想法是我们有一个具有树结构的数据类型,并且我们希望在每个元素中存储该项目所在的级别。所以在level 属性的didSet 中,我们还要设置孩子的级别属性。然而我们意识到,这只有在使用forEach 时才有效,而在使用for .. in 时无效。这是一个简短的例子:
class Item {
var subItems: [Item] = []
var depthA: Int = 0 {
didSet {
for item in subItems {
item.depthA = depthA + 1
}
}
}
var depthB: Int = 0 {
didSet {
subItems.forEach({ $0.depthB = depthB + 1 })
}
}
init(depth: Int) {
self.depthA = 0
if depth > 0 {
for _ in 0 ..< 2 {
subItems.append(Item(depth: depth - 1))
}
}
}
func printDepths() {
print("\(depthA) - \(depthB)")
subItems.forEach({ $0.printDepths() })
}
}
let item = Item(depth: 3)
item.depthA = 0
item.depthB = 0
item.printDepths()
当我运行它时,我得到以下输出:
0 - 0
1 - 1
0 - 2
0 - 3
0 - 3
0 - 2
0 - 3
0 - 3
1 - 1
0 - 2
0 - 3
0 - 3
0 - 2
0 - 3
0 - 3
从for .. in 循环调用时,它似乎不会调用 subItems 属性的 didSet。有谁知道为什么会这样?
更新: 问题不在于没有从 init 调用 didSet。之后我们更改属性(参见最后 4 行代码),两个深度属性中只有一个会将新值传播给子项
【问题讨论】:
-
我会说这种行为非常复杂,足以保证一个功能。一方面,它消除了关于它是否在
init中被调用的任何疑问。 -
这是一个已知错误:bugs.swift.org/browse/SR-419。使用闭包(正如其他人所指出的,
defer)逃避了(当前已损坏的)语义分析,该分析阻止了从自身内部调用didSet观察者;for item in subItems { { item.depthA = depthA + 1 }() }也可以。
标签: swift foreach for-in-loop didset