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
集。因为当 属性 结构的值更改基本上意味着创建新结构,并复制所有未更改的字段。
假设我有 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
集。因为当 属性 结构的值更改基本上意味着创建新结构,并复制所有未更改的字段。