Swift didSet 没有触发

Swift didSet does not fire

假设我有 class 个具有 3 个属性的 ExerciseSet:id、name、isEnabled。

我有一个对象数组 class:

var exerciseSets: [ExerciseSet] = [] {
    didSet {
        ExerciseSet.syncWithPList(updatedSets: exerciseSets)
    }
}

我在代码的某处执行了以下操作:

exerciseSets[index].isEnabled = !exerciseSets[index].isEnabled

但是在这种情况下 didSet 不会触发。只有我这样写:

let set = exerciseSets[index]
set.isEnabled = !set.isEnabled
exerciseSets[index] = set

为什么会这样?我能以某种方式使用前一个选项吗?后面那个好像很啰嗦,讨厌

didSet 触发器适用于集合,但不适用于其内容。换句话说,更改存储在集合中的对象会触发块,但更改对象的内容不会。这就是为什么您的第一个选项不起作用而第二个选项起作用的原因。

仇恨是一个强烈的词:)

这一行:

exerciseSets[index].isEnabled = !exerciseSets[index].isEnabled

你实际上并没有直接改变你的exerciseSets数组中的任何东西,你正在改变一个特定的 ExerciseSet 该数组中的项目。

比较一下:

let set = exerciseSets[index]
set.isEnabled = !set.isEnabled
exerciseSets[index] = set

此处您正在更改 exerciseSets 数组中的一个实际项目,因此 didSet 被触发。

你能做点什么吗?好问题 :) 您需要以某种方式更新 exerciseSets 数组以强制 didSet 所以我认为您不能比上面的三行更短。但愿我是错的。

是的,与其说是一个答案不如说是一个评论,希望你无论如何都能使用它。

这很可能是因为 ExerciseSet 是一个 class,这意味着它是一个引用类型。

只需将引用类型变量视为存储数字即可。然后这些数字指向实际 ExerciseSet 在内存中的位置。换句话说 [ExerciseSet] 本质上是一个数字数组。

当你这样做时:

exerciseSets[index].isEnabled = !exerciseSets[index].isEnabled

您没有更改数组中的任何 "numbers"。您只在特定索引处查找 "number",然后使用该 "number" 查找 ExerciseSet 对象。之后,你设置了一个属性的ExerciseSet.

如你所见,你根本没有修改数组中的"number"!

另一方面,您的第二段代码调用 didSet 因为您告诉它丢弃特定索引处的元素并将指向 "number" 17=] 在该索引处。由于您正在取出数组的一个元素并将某些元素放回原处,因此您正在 更改 数组本身!因此,didSet被调用。

为什么会这样?

didSet 在您更改 属性 的 值时触发,例如当数组本身发生变化时触发。

这里

exerciseSets[index].isEnabled = !exerciseSets[index].isEnabled

更改 属性 数组中的某些对象,但数组保持不变 ,并且包含相同的对象。所以 didSet 不会被调用。

我能以某种方式使用前一个选项吗?

不,你不能。使用后者。

编辑:我检查了@martin-r 建议使用 ExerciseSet 的结构,它有效,调用了 didSet 集。因为当 属性 结构的值更改基本上意味着创建新结构,并复制所有未更改的字段。