Is there a way to "unbind" variables/objects in SwiftUI

Viewed 526

The best comparison I can make is that of the iPhone Contacts app that comes with all phones.

When the user starts the app it lists all the contacts. A user can select a contact and the "Detail View" for the contact is shown. Lastly, the user can then select to edit the contact and goes to an "Edit Detail View". Simple...

One of the features I have in my app is exactly the same thing.

  1. I present a list to a user and the user can click on any items on the list.

  2. Once they click the item they can view the details for that item on the "Detail View".

  3. User has the ability to 'Edit' the items where now they can enter modifications to the item via text fields in the "Edit Detail View".

  4. The user now can 'Save' or 'Cancel' their modifications/edits if they want to, which would navigate them back to the "Detail View".

Again Simple just like the Contacts app.

So here is the issue: The 'Save' works flawlessly since I'm passing the Object as a Binding variable:

@Binding var cigar: Cigar

When a text field is changed, the modification will reflect the change back in the "Detail View" after the user presses 'Save', which is the desired outcome.

The issue tho is that even if the user clicks 'Cancel' the changes in the text field are still quote-unquote "saved", which is no the desired outcome. I imagine that is because I am using a @Binding variable and the variable changes in realtime.

So my question is, is there any way to "unbind" or discard the changes that were made to a @Binding variable/object when the user clicks 'Cancel' or wants to discard the changes/edits they made?

Can some please help, or if you can suggest a better approach to achieve the outcome.

1 Answers

Binding is a direct reference to source of truth, so making edit you modify directly original data, so making unbound on cancel, ie after changes have been applied, have no sense even if it would be possible (but it is not).

As far as you have stateful editing (ie applied by fact of Save action), you need explicit local storage for those data.

Here is a possible approach (in pseudo-code)

struct SomeView: View {

   @Binding var cigar: Cigar

   @State private var editingCigar: Cigar

   init(cigar: Binding<Cigar>) {
      self._cigar = cigar
      self._editingCigar = State(initialValue: cigar.wrappedValue)
   }

   var body: some View {

     // ... work here with `editingCigar`

     Button("Save") { 
        // !! Copy back edited cigar explicitly
        self.cigar = editingCigar
     }

     Button("Cancel") {
        // just close w/o touching self.cigar
     }
  }
}
Related