在didSet中使用循环时,我们遇到了这种奇怪的行为。我们的想法是,我们有一个具有树结构的数据类型,并且在每个元素中我们想要存储该项所处的级别。因此,在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当从一个didSet循环调用subItems属性时,它似乎不会调用for .. in属性的for .. in。有人知道为什么会这样吗?
更新:问题不是没有从init调用didSet。我们在之后更改属性(请参阅最后4行代码),只有两个深度属性中的一个将新值传播给子属性。
发布于 2018-02-13 13:23:34
如果使用延迟更新任何可选属性或进一步更新已初始化的非可选属性,并且在调用任何超级init方法之后,则将调用您的willSet、didSet等。
for item in subItems {
defer{
item.depthA = depthA + 1
}
}当您使用forEach时,它会与元素进行kindOf“契约”,因为它是一个与不同的实例方法。在循环中,它触发变量的didSet。以上情况适用于我们使用循环的地方,必须手动触发didSet。
这解决了我认为的问题。希望能帮上忙!
发布于 2018-02-13 13:16:16
在init中,似乎没有调用didSet。
在Swift REPL上尝试了这一行
class A { var a: Int { didSet { print("A") } }; init() { a = 5 } }然后被称为A()
不调用didSet
但
A().a = 7发现didSet被称为
因此,解决方案是创建一个函数(更倾向于final),这使您需要在didSet中添加效果。然后从didSet和init调用它。你可以把这个放到你的课上。
final func updateA() {
// Do your "didSet" here
}
var a: Int {
didSet {
updateA()
}
}
init() {
a = 5
updateA()
}所以在你的情况下:
func updateDepthA() {
for item in subItems {
item.depthA = depthA + 1
}
}
var depthA: Int = 0 {
didSet {
updateDepthA()
}
}
...
init(depth: Int) {
self.depthA = 0
updateDepthA()
...https://stackoverflow.com/questions/48767328
复制相似问题