didSet中的循环

M. *_*ick 5 foreach for-in-loop swift didset

当在didSet中使用循环时,我们遇到了这种奇怪的行为。这个想法是,我们有一个带有树结构的数据类型,并且在每个元素中我们都想存储该项目所在的级别。因此,在level属性的didSet中,我们还将设置子级的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()
Run Code Online (Sandbox Code Playgroud)

运行此命令时,将得到以下输出:

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
Run Code Online (Sandbox Code Playgroud)

for .. in循环中调用它时,似乎不会调用subItems属性的didSet 。有谁知道为什么会这样吗?

更新:问题不在于未从init调用didSet。之后,我们更改属性(请参阅代码的最后4行),并且只有两个depth属性之一将新值传播给子级

Age*_*ith 3

如果您使用 defer 来更新任何可选属性或进一步更新已初始化的非可选属性,并且在调用任何 super init 方法之后,将调用 willSet、didSet 等。

        for item in subItems {
            defer{
                item.depthA = depthA + 1
            }
        }
Run Code Online (Sandbox Code Playgroud)

当您使用forEach时,它会使 kindOf 与元素“契约”,并且因为它是一个实例方法,与for .. in循环不同,所以它会触发变量的didSet 。上面的情况适用于我们使用循环的地方,我们必须手动触发didSet

这解决了我认为的问题。希望能帮助到你!!