#ios #swift #swiftui
Вопрос:
В моем коде значение «окончательного» переключателя основано на сложной логике внутри модели представления. Например, пользователь включает переключатель, но логика может отключить его, если определенные условия не выполняются (здесь ниже упрощено сравнение чисел). Проблема: после того, как пользователь включит переключатель, onChange
он будет уволен, и если логика обнаружит, что он должен быть выключен, onChange
он будет уволен еще раз, потому что есть изменение (на этот раз не внесенное пользователем).
Например, если сгенерированное случайное число равно 5, то консоль выведет следующие инструкции (8 приходит после второго вызова):
on change called shouldUseToggle called 5 on change called shouldUseToggle called 8 onChange(of: Bool) action tried to update multiple times per frame.
Я хотел бы избежать этого и заставить onChange
реагировать только на изменения пользователя, а не на изменения, которые исходят из модели представления. Есть ли способ сделать это ? Или, может быть, другой способ решить эту проблему ?
import SwiftUI
struct ContentView: View {
@StateObject var myViewModel = MyViewModel()
var body: some View {
VStack(spacing: 0) {
Toggle("Use xyz ?", isOn: $myViewModel.turnToggleOn).onChange(of: myViewModel.turnToggleOn, perform: { userTurnedOn in
print("on change called")
myViewModel.shouldUseToggle(userTurnedOn: userTurnedOn)
})
}
}
}
class MyViewModel: ObservableObject {
@Published var turnToggleOn = false
func shouldUseToggle(userTurnedOn: Bool) {
///some complex logic comes here, for simplicity I use random numbers
print("shouldUseToggle called")
let x = Int.random(in: 0..<10)
print(x)
if userTurnedOn {
turnToggleOn = x > 5
} else {
turnToggleOn = x > 3
}
}
}
Комментарии:
1. Это может быть лучше для пользователя, если опция недоступна для включения, этот элемент управления следует отключить. Другими словами, используйте сложную логику, чтобы определить, следует ли включать переключатель, а не запускать его после того, как пользователь попытается его изменить.
2. хороший момент, но для типичного случая — в моем случае я дополнительно показываю предупреждение с указанием причины, по которой оно недоступно, что было бы невозможно, если переключатель отключен
Ответ №1:
Используйте пользовательскую привязку и вызывайте свою логическую функцию непосредственно из привязки.
struct ContentView: View {
@StateObject var myViewModel = MyViewModel()
var body: some View {
VStack(spacing: 0) {
Toggle("Use xyz ?", isOn: Binding(get: {myViewModel.turnToggleOn}, set: {
myViewModel.turnToggleOn = $0;
myViewModel.shouldUseToggle(userTurnedOn: $0)
}))
}
}
}
class MyViewModel: ObservableObject {
var turnToggleOn = false
func shouldUseToggle(userTurnedOn: Bool) {
///some complex logic comes here, for simplicity I use random numbers
print("shouldUseToggle called")
let x = Int.random(in: 0..<10)
print(x)
if userTurnedOn {
turnToggleOn = x > 5
} else {
turnToggleOn = x > 3
}
}
}