Property Observers in Swift — How to Use willSet and didSet

You create a class. You create a property. You know this is only the beginning. There is so much more you can do. You can make a property as badass as you want. Property observers are one way to power them up. They let you watch the flow of a property as it changes and decide what happens at each step of the way.

Let’s start with a Ghost class:

  • It has a stored property (variable) called description, that is of type String, and is initialized with a default value of “scary.”
  • An instance of Ghost is created below, with frightening results.
class Ghost {
  var description: String = "scary"
}
let evilGhost = Ghost()
print ("I'm a \(evilGhost.description) ghost!") 
//I'm a scary ghost!

Ghosts sometimes have a change of heart (?). You change the evilGhost instance property to something a bit less scary.

evilGhost.description = "friendly"
print ("I'm now a \(evilGhost.description) ghost!")
//I'm now a friendly ghost!

Can you really trust a ghost who suddenly says that it is friendly? You might want to know when this change is about to occur and what happens when it does. willSet and didSet property observers keep you in the loop of this change.  

willSet Observer

The willSet property observer activates when a property value is about to be changed. You add curly braces after the property and put it inside them.

var description: String = "scary" {
  willSet {
    print ("I'm going to become \(newValue)")
  }
}

newValue is the default variable name for what the new property value will become. If you have an undying desire to be creative with variable names, you can add in an original name after the willSet.

var description: String = "scary" {
  willSet(myAwesomeNewValue){
    print ("I'm going to become \(myAwesomeNewValue)")
  }
}

Let’s add in that willSet observer into our Ghost class and get some action going!

class Ghost {
  var description: String = "scary" {
    willSet {
      print ("I'm going to become \(newValue)")
    }
  }
}
let evilGhost = Ghost()
print ("I'm a \(evilGhost.description) ghost!") 
//I'm a scary ghost!

The willSet property is a go. But nothing happens! This is because a property observer is only called when there is a change in the property’s value. No change, no magic. Let’s actually change it.

class Ghost {
  var description: String = "scary" {
    willSet {
      print ("I'm going to become \(newValue)")
    }
  }
}
let evilGhost = Ghost()
evilGhost.description = "friendly"
print ("I'm a \(evilGhost.description) ghost!") 
//Print results
//I'm going to become friendly.
//I'm a friendly ghost!

The evilGhost now tells you it is about to change, and then it does. The above example is just a simple print statement, but you can add whatever functionality you want on that “about to change moment.” Maybe you’ll have the ghost perform a super cool pose as it is about to change.

didSet Observer

The didSet property is created in the same way.

var description: String = "scary" {
  didSet {
    print ("I used to be \(oldValue)")
  }
}

Similar to willSet, the default variable name is oldValue, but again, you can let your imagination run wild.

var description: String = "scary" {
  didSet(myAwesomeOldValue){
    print ("I used to be \(myAwesomeOldValue)")
  }
}

You can combine the oldValue with the actual var name of the property you set. The result is a very talkative ghost!

var description: String = "scary" {
  didSet {
    print ("I used to be \(oldValue) but now I'm \(description)")
  }
}

didSet is called immediately after the property you set (description) has been changed.

Combining willSet and didSet

You don’t have to use both, but c’mon… of course you will! Here’s the fantastical ghostly results when everything is added together.

class Ghost {
  var description: String = "scary" {
    willSet {
      print ("I'm going to become \(newValue)")
    }
    didSet {
      print ("I used to be \(oldValue) but now I'm \(description)")
    }
  }
}
let evilGhost = Ghost()
evilGhost.description = "friendly"
print ("I'm a \(evilGhost.description) ghost!")
//Print results
//I'm going to become friendly.
//I used to be scary but now I'm friendly. 
//I'm a friendly ghost!

Here’s what is happening:

  1. An instance of the Ghost class called evilGhost is created
  2. You attempt to change the evilGhost instance’s property called description to “friendly”
  3. As the instance property is about to be changed, the willSet property observer prints out “I’m going to become \(newValue)”
  4. The instance property is changed
  5. Right after the instance property has been changed, the didSet property observer prints out “I used to be \(oldValue) but now I’m \(description)”
  6. The property has been changed, both observers did their thing, and then the final print statement I added at the end “I’m a \(evilGhost.description) ghost!” is called

Go out and set!

Observe and set. Observe and set. Properties will become more versatile than you could ever imagine!

Leave a Comment

Your email address will not be published. Required fields are marked *