Swift 4 property observers: responding to changes in property values and managing state

Swift tutorials by iosbrain.comWe’re going to learn about a feature of Swift called “property observers” that help developers manage app state. You can easily add code to monitor changes to Swift native type property values as well as your own custom type property values. Remember that you can gain insight into an application by looking at its state: the data values stored in all properties of the app at a specific point in time. Getting a grip on app state, therefore managing complexity, is one of the biggest challenges in computer science. Property observers are one technology that help you get a grip. In today’s article, I’ll explain this Swift feature, demonstrate its usage with runnable examples of Swift code, show you how I built an app which relies on property observers, and provide you a list of other Swift technologies that help you manage app state and complexity. Here’s my sample app in action:

Download the Xcode 9 project and playground, both written in Swift 4, from GitHub so you can follow along with my discussion.


Introduction

Apps store data in variables. Often, though not exclusively, app data is provided by users of the app, whether human or not, as “input.” Remember there are apps that, say, help people manage their bank accounts and there are embedded apps that monitor the activities of, say, automobile engines.

In computer science, the contents of these variables at any moment in time during the app’s lifetime, i.e., while the app is executing, determine the app’s state. If you could make a list of all an app’s data at a given point in time, you’d have a snapshot roughly describing what is happening in the app at that moment.

I use the term “roughly” because, computer science definitions or not, an app’s state is more than just a list of its data at a point in time. The context in which the app is running — call it the app’s “configuration” — must also be taken into account.

Think about a word processing application. Because of multiprocessors and threaded code, the word processor may be doing a number of complex tasks at the same time: the user is dictating text into a new document using a Bluetooth headset; sometimes the user types text with the keyboard (input is not exclusively through the Bluetooth headset); text is being constantly checked for syntax and grammatical errors; the stock image/shapes library was updated by the vendor so the app is now downloading a set of files over the Internet; the social media plugin is monitoring for new likes and tweets on articles the user has previously written and posted using the app; etc.

I think you get the point. A “simple” word processing app is not so simple. In fact, defining all the possible states that such an application can take on is computationally impossible. Most applications nowadays fall into this not-so-simple category. They can enter stochastic (random) states no matter how hard developers try to manage complexity. (I love quoting my own publications, as in the link for the term “stochastic (random) states.”)

Controlling complexity

Properties
Remember that in the simplest terms, Swift classes are made up of properties and methods, or what humans would call data and behaviors, respectively. This data contains information about the state of your application. Many of you have written applications that store, at least temporarily, pieces of data like a person’s username, a user’s account number, the current temperature in a user’s neighborhood, how many items are in a user’s shopping cart, the gross value in dollars of their shopping cart, etc.

Monitoring property state
Did you know that Swift can notify you when when a property (member variable) of one of your classes or structs 1) will be changed and 2) has changed? Swift gives you the opportunity to manage your application’s state. You have to write a little bit of code, but it’s intuitive and the syntax is very readable, thus showing again how expressive and powerful the Swift language can be. Apple calls this property state monitoring aspect of the Swift language “property observers.” Today, I’ll explain how property observers work, and discuss when you should use them, how you shouldn’t abuse them, and show you plenty of example code to get you up and running with this elegant and straightforward feature of the Swift language. To get you down in the trenches, I’ll build a fully-functional temperature conversion app which allows users to transform Fahrenheit values to Celsius values and Celsius values to Fahrenheit values.

Property observers to the rescue

Code complexity has to be controlled with a combination of features. I’ll summarize many of the tools available later. Today, we’ll concentrate on Swift property observers.

Harmony starts at home. By that I mean that you can’t conquer an entire codebase’s complexity at once. You need to divide and conquer. The best app architectures are the ones in which designers and developers solve problems by creating solutions made up of relatively small components that interact using well-defined interfaces. Classes are a great example of such small components that interact using well-defined interfaces. If you’ve been reading my blog, you know by now that I like to use small and well-defined classes.

By adding property observers to your classes judiciously, you can start controlling complexity as you build your solution.

You apply property observers to class member variables (properties). These observers inform you every time a property is about to be changed and when the property is actually changed. This is your chance to control complexity. Think about it: You can get automatically notified when the property or properties of a class instance (object) will and have changed. You’re getting notified of state changes.

Definitions
According to Apple’s Swift 4.1 documentation:

Property observers observe and respond to changes in a property’s value. Property observers are called every time a property’s value is set, even if the new value is the same as the property’s current value. …

You have the option to define either or both of these observers on a property:

  • willSet is called just before the value is stored.
  • didSet is called immediately after the new value is stored.

If you implement a willSet observer, it’s passed the new property value as a constant parameter. You can specify a name for this parameter as part of your willSet implementation. If you don’t write the parameter name and parentheses within your implementation, the parameter is made available with a default parameter name of newValue.

Similarly, if you implement a didSet observer, it’s passed a constant parameter containing the old property value. You can name the parameter or use the default parameter name of oldValue. If you assign a value to a property within its own didSet observer, the new value that you assign replaces the one that was just set. …

#ad

Simple example of property observers
I’ve written some simple examples of property observers so you can understand their basic functionality. Let start with a struct in which I accept the the default parameter names of oldValue and newValue:

Here’s the output from line 21:

Now I’ll use property observers with a class. Instead of accepting the default parameter names of oldValue and newValue, I’ll define my own — in parentheses immediately following the willSet and didSet observer declarations. Notice that, since the name variable is not optional, I had to add an initializer (init):

Here’s the output from line 25:

Intermediate conclusions
After reviewing the previous two property observer examples, you should have a cursory understanding of how they work. Let me make a few observations after modifying the class named “Being:”

Here’s the output from lines 27 and 28:

As to the intermediate conclusions… Notice that I was able to change the value of a property in a property observer (in didSet). I sometimes wonder if that’s good practice, but I can envision a use case in which changing a property in it’s own observer is legitimate, like rounding a number to a specific number of digits, or perhaps adding a prefix like “Mrs. ” or “Mr. ” to a person’s name.

Notice that trying to change a property’s value in willSet does not work, and Xcode will catch that scenario and warn you with the message: “Attempting to store to property ‘name’ within its own willSet, which is about to be overwritten by the new value.” Isn’t that self-explanatory? See this image:

Click to enlarge

When I first learned about property observers, I had the notion that they would be limited to atomic operations and simple operations. They’re not. I can do pretty much anything in a property observer, from changing the observed property’s value to spinning off a new thread:

You can even update the user interface (UI) from a property observer. Why am I bringing this up?

I see property observers as a very powerful and elegant tool that should be used only for the right reasons and/or only when necessary.

My mantra is “keep it simple and clean” (Occam’s razor). My advice to you is to use property observers for simple tasks like:

By “managing state,” I’m referring to scenarios like performing mathematical calculations or string manipulations directly related to the property and/or its companion properties.


Doing things like updating the UI directly from willSet or didSet in an app’s classes for core business logic is asking for trouble. Your code for app logic and your code for UI will become too tightly coupled and you’d be breaking the Model-View-Controller (MVC) design pattern. If you feel you absolutely must update the UI from a property observer, use something like messaging via NSNotificationCenter. I discuss NSNotificationCenter, loose coupling, and tight coupling in my article at this link.

I’m throwing a lot at you in this article, so I don’t want to get caught up in too many details. There is one last thing I should mention: how and the order in which property observers are called when inheritance is involved. I leave it to you to read Apple’s discussion on this subject.

Property observers support custom types
Property observers don’t only apply to Swift’s built-in types like Int, Float, and Bool. You can define property observers for your own custom types.

You’ll notice in my sample app that I only call a method from my property observers if the property is being changed. In order to determine if a property is being assigned a new value, you need to use the != operator. What do you have to do to make your custom type support the != operator? Do you remember? Did you read my article on Swift generics?

If you don’t remember the answer to the question “What do you have to do to make your custom type support the != operator?,” the answer is to make your custom type conform to the Equatable protocol:

Here’s the output from line 85:

Sample app demonstrating property observers

In order to demonstrate property observers, I’ve designed and developed a fully-functional temperature conversion app (Fahrenheit to Celsius and Celsius to Fahrenheit). Given the rather lengthy discussion leading up to this point, I won’t explain the app’s commonplace structural details, i.e., storyboard, IBOutlets, IBActions, etc. Given the fact that the app is based on the Xcode 9 Single View App project template, most of you know how to build this sample app. First I’ll discuss how property observers are used in the app and then I’ll show you the most important app code. After reading this section and the preceding discussion, I would hope that you have gained a basic grasp of property observers. Download the Xcode 9 project and playground, both written in Swift 4, from GitHub so you can follow along with my discussion.

This app makes what I consider to be common sense and legitimate use of property observers for managing the state of the app’s core business logic class, Temperature. Remember that by “managing state,” I’m referring to scenarios like performing mathematical calculations or string manipulations directly related to a property and/or its companion properties.

I making sure that the state of my Temperature class’s member properties, fahrenheit and celsius are always “synchronized.” Since people all over the world use both temperature types, I want to always be able to provide the currently stored temperature in both fahrenheit and celsius. Since temperature fluctuates over time, a user of my class would continually be updating they’re preferred temperature type property. No matter which temperature type property they update, either fahrenheit and celsius, the other type will be updated with its corresponding, respective, and properly-converted value. The state of my class’s properties is guaranteed to be correct/accurate because of property observers. And no, I haven’t tested it exhaustively for every possible contingency. This is a sample app. Please read the licensing agreement under which you must use the app code and project.

#ad

Note that while I generally dislike the idea of using a property observer to update the UI, I’ve done so in the sample app using a loosely-coupled solution, namely, messaging via NSNotificationCenter. See my article on writing loosely coupled code using NSNotificationCenter.

Here’s how the app works:

Here’s the core business logic class in file Temperature.swift:

Here’s the one and only UIViewController in file ViewController.swift:

Wrapping up

I hope y’all enjoyed the discussion of property observers. Please remember to use them judiciously and not overuse or abuse them. Property observers are not the only Swift feature that help in managing app state and complexity. Here’s a list of other Swift technologies covered on this website that also help you tackle state and complexity:

Above all, remember to enjoy life, not just work!

#ad

Author: Andrew Jaffee

Avid and well-published author, software engineer, designer, and developer, now specializing in iOS mobile app development in Objective-C and Swift, but with a strong background in C#, C++, .NET, JavaScript, HTML, CSS, jQuery, SQL Server, MySQL, Oracle, Agile, Test Driven Development, Git, Continuous Integration, Responsive Web Design, blah, blah, blah ... Did I miss any fad-based catch phrases? My brain avatar was kindly provided by https://icons8.com under a Creative Commons Attribution-NoDerivs 3.0 Unported license.