Swift: Property Observers
TL;DR : PropertyObservers.playground
Observing changes to variables is very easy with Swift with Property Observers. Previously with Objective-C it was necessary to take a few more steps and you had to be careful if you wanted to leverage a system like Key-Value Observing (KVO). You would first declare the property and, before it was made automatic, you had to put @synthesize statements in place to ensure the property was implemented. Then you could optionally implement the getters and setters where you could put logic for responding to changes to the variables. And if you did implement the getters and setters instead of letting @synthesize do all of the work for you, you’d want to ensure you made it KVO compatible by indicating a value will and and did change using the protocol for NSKeyValueObserving. A lot could go wrong. KVO itself was the source of a lot of confusion as it did not work as some assumed. This confusion was the source of critical bugs and was likely an incentive to make it easier to observe properties in Swift.
The syntax is Swift is simple without the need for KVO. By creating a property with the willSet and didSet observers you can insert code that can respond to changing values. For the sample Playground for Property Observers I created a class for a Person and another for Apartment. Each has a property to reference an instance of the other class. An Apartment can have a tenant and a Person can have an apartment. I wanted these values to stay in sync when just one instance was updated. I added willSet and didSet observers to both of them so that if a tenant is set on an apartment it will also set the apartment on the instance of Person.
When the tenant property is set on the Apartment it will also try to set the apartment property on the Person. But it should not set the property every time otherwise both observers would be called endlessly. Instead the other property should only be set if it is not set as intended. If the tenant is set then the Person should have the same instance of Apartment. If it is not, then it should be set to self within the observer for Apartment. I learned that trying to check the value of the other property in willSet is not going to work as the value has not changed yet. Instead I had to use didSet so that the observer would not try to run repeatedly with a changing value.
The observers also handle the case where the property is set to nil. In order to handle that scenario it is necessary to access the oldValue which I named going into the didSet observers just to make it more clear. I could have just used the default name of oldValue in both observers but I feel naming them makes the code more readable.
This is a pretty basic use of observers. Where I expect I would use these heavily is with updating views based on changes to properties. A table view may have cells displaying a set of objects and if one of these objects is updated it would be possible to tell the view controller about the change so it could look up the indexPath for that cell, determine if it is currently visible and update the cell if it is.
One app I built was a music player and each time a track changed or the playback position moved a notification would be posted and various view controllers which managed different screens in the app would update views as needed. I considered KVO but that would have required more details to be handled. It is much easier to observer an application notification for changes. If I were to rebuild that app with Swift I could make it much more simple with Property Observers.
Global and Local
The example with Person and Apartment classes uses Type Properties. The Apple docs explain that observers can also be added to global or local variables, so I added a section at the bottom to declare a variable for name and set the value a few times to show how the observers could report on the changes.
Next: Lazy Properties