在didSet中循环

时间:2018-02-13 12:53:29

标签: swift foreach for-in-loop 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()

当我运行时,我得到以下输出:

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

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

更新: 问题不在于没有从init调用didSet。之后我们更改了属性(参见最后4行代码),只有两个深度属性中的一个会将新值传播给子代

2 个答案:

答案 0 :(得分:3)

如果你使用defer,更新任何可选属性或进一步更新你已经初始化的非可选属性,并且在你调用任何超级init方法之后,那么你的willSet,didSet等将会被称为。

        for item in subItems {
            defer{
                item.depthA = depthA + 1
            }
        }

当您使用 forEach 时,它会使kindOf&#34;合同&#34;使用元素,因为它是一个不像 for .. in 循环的实例方法,它会触发变量的 didSet 。以上情况适用于我们使用循环的地方,我们必须手动触发 didSet

这解决了我认为的问题。希望它有所帮助!!

答案 1 :(得分:0)

似乎在 private void dgvSuppliers_RowEnter(object sender, DataGridViewCellEventArgs e) { var supplier = ((Supplier)dgvSuppliers.Rows[e.RowIndex].DataBoundItem); if (supplier == null) return; ShowSupplierPlants(supplier.SupplierID); } private void ShowSupplierPlants(int supplierID) { var plantData = AppData.SupplierPlants.Where(x => x.SupplierID == supplierID); //Get selected Suppliers Plant Data. if (plantData.Any()) bsSuppliersPlants.DataSource = plantData; else bsSuppliersPlants.DataSource = new List<SupplierPlant>(); dgvSupplierPlants.Refresh(); } 中,没有调用didSet。

在Swift REPL上试过这一行

init

然后调用class A { var a: Int { didSet { print("A") } }; init() { a = 5 } }

didSet未被调用

但是

A()

发现didSet被称为

所以,解决方案是创建一个函数(最好是A().a = 7 ),这样你需要放入final。然后从didSetdidSet调用它。你可以把它放在你的班上。

init

所以在你的情况下:

final func updateA() {
    // Do your "didSet" here
}

var a: Int {
    didSet {
        updateA()
    }
}

init() {
    a = 5
    updateA()
}