I have a Model in SwiftUI handling my person model. To be able to store draft persons in the editor in the View(s), I have two objects:
@Published var person: Person
@Published var draftPerson: Person
In the UI, I am only changing the draftPersons until the user clicks on "Save", which stores the draftPerson as the person. In the onAppear method of the editor, I reset the draftPerson to the person.
Now I want to disable the "Save" button of the Editor and therefor introduced a bool "modified" in the Model. Using a pipeline, I want to set the modified to true, if and as long as the draftPerson is not equal to person, by doing the following:
$draftPerson.map { draftPerson in
return draftPerson != self.person
}
.assign(to: \.modified, on: self)
.store(in: &cancellables)
It looks like it is working on first glance, but if I change something in a textField, the value of modified is only set to true after the second change in the field. Vice versa, if I delete the typed values, it is only set back to false after I delete one more character as were originally there.
Question 1: Is there another "best practice" to handle changes in draft objects and deactivating the "Save" button in SwiftUI?
Question 2: Why is the pipeline "one change behind"?
Thanks a lot for your input.
Edit: I created a separate part of the App focusing only on the pipeline and realized that it is indeed working as intended if I remove my other pipelines. I have to check now in detail. Nevertheless, I will stick with my first question: Is there anything I can do better?
Please find the code here on Github
You could declare another @Published
property and combine the two person and draftPerson publishers and publish whether they are the same, like this:
@Published var person: Person
@Published var draftPerson: Person
@Published var saveDisabled: Bool = true
public init() {
// all init code
Publishers.CombineLatest($person, $draftPerson)
.map { $0 == $1 }
.assign(to: &$saveDisabled)
}
But essentially it is not needed and a computed property will do the same job:
var saveDisabled: Bool {
person == draftPerson
}
Because both person and draftPerson are marked @Published
each time one of them changes the View
will be notified of the change so it will also pick new value of saveDisabled.