Blog

Swift Tip: Lightweight Observation

When you have a static view hierarchy with dynamic data, you can use the built-in didSet property observer to observe changes in the data. For example, when we display the profile of a user in our app, we might have a view controller that looks like this:

class ViewController: UIViewController {
    @IBOutlet var name: UILabel?
    @IBOutlet var postCount: UILabel?
    @IBOutlet var followerCount: UILabel?
    @IBOutlet var adminBadge: UIView?

    // ...
}

When displaying a new profile, or when the profile data has changed (for example, the follower count increases), we’d like to update the views. Rather than exposing the views individually, we create a struct to hold the changeable data:

struct Profile {
    var name: String = ""
    var postCount: Int = 0
    var followerCount: Int = 0
    var isAdmin: Bool = false
}

We then create a property that holds a value of Profile, and whenever the property changes, we update the views:

class ViewController: UIViewController {
    // ...

    var profile: Profile = Profile() {
        didSet {
            updateViews()
        }
    }

    func updateViews() {
        name?.text = profile.name
        postCount?.text = "\(profile.postCount)"
        followerCount?.text = "\(profile.followerCount)"
        adminBadge?.isHidden = !profile.isAdmin
    }
}

When we call updateViews from viewDidLoad, we’ll always have our user interface in sync with the profile property. We can set it to a new value, but because of the way structs work, we can even do something like this:

var vc: ViewController = // ...
vc.profile.postCount += 1

The above code will trigger the didSet, and the views will update accordingly. This is useful from outside the view controller, but even inside a view controller we can now change the profile property and have our views update automatically. The beauty of this technique is that it’s incredibly simple: we don’t need a reactive framework, KVO, or anything else.

Of course, there are some downsides too:

  • It’s not straightforward to dynamically add and remove views (however, we can easily show and hide views)
  • We don’t receive fine-grained updates, but instead update all the views even if only a single property has changed.

That said, if your view controller is simple enough, you can consider the didSet approach. It has worked well for us in many projects.

In Swift Talk episodes 61 and 63 (both public) we show a way to get more fine-grained updates, and to share data between view controllers. Episodes 73 (public) and 74 show a way to create view bindings in pure Swift.

In our book App Architecture, observation of changes is an essential aspect of the architectural patterns we look at, and it’s discussed in much greater depth.

If you’d like to become a Swift Talk subscriber, please do! — we have monthly or yearly plans, for individuals or teams, with new episodes every week. 🤓


Stay up-to-date with our newsletter or follow us on Twitter.

Back to the Blog

recent posts