斯威夫特的财产监督员不会被级联调用

时间:2016-12-02 18:26:42

标签: swift3 property-observer

我们说我有一个像这样简单的树状结构:

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的祖先也是如此。 但是,它的后代(parentchild)不是。 请注意,我一直在使用grandChild观察相同的结果(当然,调整上面的代码时要考虑到willSet还没有改变)。

有人能指出我在这里失踪了吗?

我可以用非常类似的方法用计算属性做我想做的事。 但我发现它不如有财产观察者那样优雅,如果可能的话宁可避免它。 不过,这个片段可以完成任务。

self.ancestor

1 个答案:

答案 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