0

假设我有具有 3 个属性的练习集类:id、name、isEnabled。

我有一个此类的对象数组:

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

为什么会这样?我可以以某种方式使用前一个选项吗?后一个似乎很冗长,我讨厌它。

4

4 回答 4

2

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

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

当你这样做时:

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

您没有更改数组中的任何“数字”。您只在特定索引处查找“数字”,然后使用该“数字”来查找ExerciseSet对象。之后,您设置ExerciseSet.

如您所见,您根本没有修改数组中的“数字”!

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

于 2016-11-16T08:04:12.263 回答
1

仇恨是一个强烈的词:)

在这一行:

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

您实际上并没有直接更改exerciseSets数组中的任何内容,而是更改了该数组中特定 ExerciseSet项目的某些内容。

将其与以下内容进行比较:

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

在这里,您正在更改数组中的实际项目exerciseSets因此didSet被解雇。

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

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

于 2016-11-16T08:04:05.100 回答
0

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

于 2016-11-16T08:03:33.303 回答
0

为什么会这样?

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

这里

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

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

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

不,你不能。使用后者。

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

于 2016-11-16T08:04:46.697 回答