Перегибы свойств Свифта не вызывают в каскаде
Допустим, у меня есть простая древовидная структура, подобная этой:
class Tree {
weak var ancestor: Tree?
var children = [Tree]()
}
Каждый узел дерева хранит ссылку на своих потомков, а слабый (чтобы избежать циклов ссылок) - на самого старого предка.
Я хотел бы автоматически обновлять свойство ancestor всех узлов поддерева всякий раз, когда я устанавливаю его в корень.
let grandParent = Tree()
let parent = Tree()
let child = Tree()
let grandChild = Tree()
child.children.append(grandChild)
parent.children.append(child)
grandParent.children.append(parent)
// Should set ancestor in the whole hierarchy.
grandParent.ancestor = grandParent
Я пытался добиться этого с помощью наблюдателей свойств, перебирая потомки узла всякий раз, когда его предок установлен так, что значение распространяется, но не заметил ни didSet
ни willSet
вызывается прошло первый ребенок. Вот код, с которым я столкнулся:
weak var ancestor: Tree? = nil {
didSet {
for child in self.children {
child.ancestor = self.ancestor
}
}
}
Как и ожидалось, предок grandParent
правильно установлен, как и у parent
, Тем не менее, те его потомков (child
а также grandChild
) не. Обратите внимание, что я наблюдаю тот же результат с willSet
(конечно, корректируя приведенный выше код, чтобы принять во внимание, что self.ancestor
не изменился бы еще).
Может ли кто-нибудь указать мне, что я здесь скучаю?
Я мог делать то, что я хочу с вычисленными свойствами, с очень похожим подходом. Но я нахожу его менее элегантным, чем тот, который имеет наблюдателей за недвижимостью, и предпочел бы избежать этого, если возможно Тем не менее, этот фрагмент делает вещи.
var ancestor: Tree? {
get {
return self._ancestor
}
set(newAncestor) {
self._ancestor = newAncestor
for child in self.children {
child.ancestor = newAncestor
}
}
}
private weak var _ancestor: Tree? = nil
1 ответ
Я видел это упомянутое ранее, и похоже, что это ошибка Swift, которая срабатывает, если вы пытаетесь установить свойство внутри willSet / didSet для другого экземпляра того же типа.
Как ни странно, синтаксис имеет значение и, кажется, работает над ошибкой. Например, я могу заставить ваш код работать, изменив didSet
к этому:
weak var ancestor: Tree? = nil {
didSet {
children.forEach { $0.ancestor = ancestor }
}
}
Он делает то же самое, но не вызывает ошибку компилятора.
ОБНОВИТЬ
Ранее это было зарегистрировано как ошибка на swift.org и все еще открыто: https://bugs.swift.org/browse/SR-419
И есть пара дополнительных комментариев, разъясняющих причину и какие обходные пути могут избежать этого здесь: https://twitter.com/uint_min/status/804795245728698368