我们说我有一个像这样简单的树状结构:
class Tree {
weak var ancestor: Tree?
var children = [Tree]()
}
树的每个节点都保留对其子节点的引用,以及对最旧的祖先的弱节点(以避免引用循环)。
每当我在子树上设置子树时,我都想自动更新子树的所有节点的祖先属性。
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
和{{1}被调用传递给第一个孩子。
以下是我遇到过的代码:
willSet
正如预期的那样,weak var ancestor: Tree? = nil {
didSet {
for child in self.children {
child.ancestor = self.ancestor
}
}
}
的祖先被正确设置,grandParent
的祖先也是如此。
但是,它的后代(parent
和child
)不是。
请注意,我一直在使用grandChild
观察相同的结果(当然,调整上面的代码时要考虑到willSet
还没有改变)。
有人能指出我在这里失踪了吗?
我可以用非常类似的方法用计算属性做我想做的事。 但我发现它不如有财产观察者那样优雅,如果可能的话宁可避免它。 不过,这个片段可以完成任务。
self.ancestor
答案 0 :(得分:3)
我之前看过这个,如果你试图在同一类型的另一个实例上的willSet / didSet中设置一个属性,它似乎是一个Swift错误。
奇怪的是,语法很重要,似乎可以解决这个问题。例如,我可以通过将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