合并:相互更新值
Combine: update values each other
这里的示例代码非常简单。滑块更新 double 值,但反之则不然。使用 Combine 如何相互更新两个或多个滑块?
struct Centimeters {
var value: Double
func updateInches() -> Double {
return value / 2.54
}
}
struct Inches {
var value: Double
func updateCentimeters() -> Double {
return value * 2.54
}
}
class SizeValueModel: ObservableObject {
@Published var centimeters: Centimeters
@Published var inches: Inches
var cancellables = Set<AnyCancellable>()
init() {
self.centimeters = Centimeters(value: 1.0)
self.inches = Inches(value: 0.393701)
$centimeters.sink {
self.inches.value = [=10=].updateInches()
}.store(in: &cancellables)
// $inches.sink {
// self.centimeters.value = [=10=].updateCentimeters()
// }.store(in: &cancellables)
}
}
struct ContentView: View {
@StateObject var model = SizeValueModel()
var body: some View {
Slider(value: $model.centimeters.value, in: 0...100, label: {
Text("\(model.centimeters.value)")
})
Slider(value: $model.inches.value, in: 0...39.3701, label: {
Text("\(model.inches.value)")
})
}
}
正如您在尝试添加当前评论的第二个 sink
时所看到的那样,您最终会在英寸和厘米之间产生循环依赖。相反,我建议您存储 一个 值并为另一个使用自定义绑定:
struct Centimeters {
var value: Double
}
class SizeValueModel: ObservableObject {
@Published var centimeters: Centimeters
var inchesBinding : Binding<Double> {
.init {
self.centimeters.value / 2.54
} set: {
self.centimeters.value = [=10=] * 2.54
}
}
init() {
self.centimeters = Centimeters(value: 1.0)
}
}
struct ContentView: View {
@StateObject var model = SizeValueModel()
var body: some View {
Slider(value: $model.centimeters.value, in: 0...100, label: {
Text("\(model.centimeters.value)")
})
Slider(value: model.inchesBinding, in: 0...39.3701, label: {
Text("\(model.inchesBinding.wrappedValue)")
})
}
}
我猜你的问题是你创建了一个无限循环,因为你正在观察两个相互改变的值。
- 英寸变化 -> 厘米得到更新
- 厘米变化 -> 英寸得到更新
- 英寸变化 -> 厘米得到更新
- 厘米变化 -> 英寸得到更新
- ...等等
@jnpdx 答案是恕我直言的正确答案(它允许您拥有单一的事实来源)
或者(可能对其他用例有用),您可以检查值是否实际更改,以避免触发无用的更新。
首先让你的结构符合Equatable
struct Centimeters: Equatable {
// ...
}
struct Inches: Equatable {
// ...
}
然后,在您的视图模型中对发布者应用修饰符,以避免在值实际未更改时触发事件。
$centimeters
.removeDuplicates()
.sink {
self.inches.value = [=11=].updateInches()
}.store(in: &cancellables)
$inches
.removeDuplicates()
.sink {
self.centimeters.value = [=11=].updateCentimeters()
}.store(in: &cancellables)
这里的示例代码非常简单。滑块更新 double 值,但反之则不然。使用 Combine 如何相互更新两个或多个滑块?
struct Centimeters {
var value: Double
func updateInches() -> Double {
return value / 2.54
}
}
struct Inches {
var value: Double
func updateCentimeters() -> Double {
return value * 2.54
}
}
class SizeValueModel: ObservableObject {
@Published var centimeters: Centimeters
@Published var inches: Inches
var cancellables = Set<AnyCancellable>()
init() {
self.centimeters = Centimeters(value: 1.0)
self.inches = Inches(value: 0.393701)
$centimeters.sink {
self.inches.value = [=10=].updateInches()
}.store(in: &cancellables)
// $inches.sink {
// self.centimeters.value = [=10=].updateCentimeters()
// }.store(in: &cancellables)
}
}
struct ContentView: View {
@StateObject var model = SizeValueModel()
var body: some View {
Slider(value: $model.centimeters.value, in: 0...100, label: {
Text("\(model.centimeters.value)")
})
Slider(value: $model.inches.value, in: 0...39.3701, label: {
Text("\(model.inches.value)")
})
}
}
正如您在尝试添加当前评论的第二个 sink
时所看到的那样,您最终会在英寸和厘米之间产生循环依赖。相反,我建议您存储 一个 值并为另一个使用自定义绑定:
struct Centimeters {
var value: Double
}
class SizeValueModel: ObservableObject {
@Published var centimeters: Centimeters
var inchesBinding : Binding<Double> {
.init {
self.centimeters.value / 2.54
} set: {
self.centimeters.value = [=10=] * 2.54
}
}
init() {
self.centimeters = Centimeters(value: 1.0)
}
}
struct ContentView: View {
@StateObject var model = SizeValueModel()
var body: some View {
Slider(value: $model.centimeters.value, in: 0...100, label: {
Text("\(model.centimeters.value)")
})
Slider(value: model.inchesBinding, in: 0...39.3701, label: {
Text("\(model.inchesBinding.wrappedValue)")
})
}
}
我猜你的问题是你创建了一个无限循环,因为你正在观察两个相互改变的值。
- 英寸变化 -> 厘米得到更新
- 厘米变化 -> 英寸得到更新
- 英寸变化 -> 厘米得到更新
- 厘米变化 -> 英寸得到更新
- ...等等
@jnpdx 答案是恕我直言的正确答案(它允许您拥有单一的事实来源)
或者(可能对其他用例有用),您可以检查值是否实际更改,以避免触发无用的更新。
首先让你的结构符合Equatable
struct Centimeters: Equatable {
// ...
}
struct Inches: Equatable {
// ...
}
然后,在您的视图模型中对发布者应用修饰符,以避免在值实际未更改时触发事件。
$centimeters
.removeDuplicates()
.sink {
self.inches.value = [=11=].updateInches()
}.store(in: &cancellables)
$inches
.removeDuplicates()
.sink {
self.centimeters.value = [=11=].updateCentimeters()
}.store(in: &cancellables)