Мы столкнулись с этим странным поведением при использовании циклов в didSet. Идея заключалась в том, что у нас есть тип данных с древовидной структурой, и в каждом элементе мы хотели сохранить уровень, на котором находится этот элемент. Таким образом, в didSet атрибута level
мы также устанавливаем атрибут level дочерних элементов. Однако мы поняли, что это работает только при использовании 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
Кажется, что он не будет вызывать didSet атрибута subItems, когда он вызывается из цикла for .. in
. Кто-нибудь знает, почему это так?
ОБНОВЛЕНИЕ: проблема не в том, что didSet не вызывается из init. После этого мы меняем атрибут (см. последние 4 строки кода), и только один из двух атрибутов глубины будет передавать новое значение дочерним элементам.
init
. - person Alexander   schedule 13.02.2018defer
) позволяет избежать (в настоящее время нарушенного) семантического анализа, который предотвращает вызовdidSet
наблюдателя изнутри самого себя;for item in subItems { { item.depthA = depthA + 1 }() }
тоже работает. - person Hamish   schedule 13.02.2018