Property Observers

Hi All,

Hope everyone is well. Just trying to get my head around property observers didSet and willSet. I get how to implement them, but not how to actually use them in a practical way.

There are plenty of examples online, but most of these simply print out the result of “oldVaule” and “newValue” in a playground demo.

Is it possible to show a practical demo of how to actually use the oldValue and newValue within the actual code itself?

I have a case where I wish to swap the value in two picker views after I save the values from the Picker.

The first value is a departure point, the second is arrival.

I also use a variable called “origin” that i use as a container to temporarily store the value of selectedDeparture.

I then set selectedDeparture = selectedArrival.

Finally i set the selected arrival to origin:

selectedArrival = self.origin

So in effective one I have added the departure and arrival airports to the array, I reverse their values as a return flight ready for the next user selection.

Is there are smarter way I can do this somehow using property observers?

Many thanks

Tariq


@State private var selectedDeparture: Int = 0       
@State private var selectedArrival = 0
@State private var origin: Int = 0

Section {
                        
                        Picker("Departure", selection: $selectedDeparture ) {
                                
                            ForEach (0..<schedule.airports.count) {
                                    
                                Text(self.schedule.airports[$0].iATA)
                            }
                        }
                        
                        Picker("Destination", selection: $selectedArrival) {
                            
                            ForEach (0..<schedule.airports.count) {
                                
                                Text(self.schedule.airports[$0].iATA)
                            }
                        }
                    }

The schedule.airports[$0}.iATA is a 3 letter code representing the airport, eg JFK.

Below the pickers in my code I have a button that will add the selected value from the pickers.

 Button(action: {schedule.addFlight(number: flightNumber, goingFrom: schedule.airports[selectedDeparture], goingTo: schedule.airports[selectedArrival])
                 self.flightNumber = ""
                 self.origin = self.selectedDeparture
                 self.selectedDeparture = self.selectedArrival
                 self.selectedArrival = self.origin
                 dismissSheet = false}, label: {
                                                                Text("Add")
                                                                
                                                            })

I have moved your post to App Development since it is a question that can be answered.

This article by John Sundell may be of assistance:

Many thanks Chris.

I’ll take a look

Tariq

I’ve managed to solve the problem after a bit of trial and error and research.

So, first of all, I have abstracted the code for setting the bindings in the picker out of the individual view to the main ViewModel (called FlightModel).

This is ViewModel conforms to the ObservableObject protocol, which I have published to the environment using @EnvironmentObject (as demonstrated in the recent tutorial). The relevant properties, ‘selectedDeparture’ and ‘selectedArrival’, are now broadcast to all views using @Published.

Hence when they are changed using the picker views, their bound-values in the ViewModel are changed accordingly.

By attaching property observes to the selectedDeparture and selectedArrival properties (didSet and willSet respectively) in the ViewModel, I am able to store their values as they are changed by the picker views.

The final piece of the puzzle was declaring two more properties in the ViewModel which would be assigned the values of the departure and arrival points in their respective property observers. These properties are ‘newArrival’ and ‘newDeparture’. Also I added one more property to count the total flights in the array.

In the main body of the ViewModel is a function for adding flights. This method is called from the same view that contains the pickers for selecting the departure and arrival airports (a flight number is also added here). The call to this method is from the action closure of this button.

The function when called will commit the values of selectedDeparture and selectedArrival (in the picker view) to the flight array (as well as flight number). It then assigns newDeparture to selectedDeparture and newArrival to selectedArrival.

This has the desired effect. Also, an improvement on the previous implementation, when the user navigated away from the tabview and then returned to the page for entering flights, the departure and arrival were reset to their original default airports. Whereas now, if the user navigates away from this tab and then comes back later to add more flights, the correct departure-arrival pair is maintained, rather than re-set back to default.