Property Observers didSet and willSet in Swift 4 – The Andela Way … - MywallpapersMobi

Property Observers didSet and willSet in Swift 4 – The Andela Way …

Homepage
The Andela Way
Sign in Get started


Property Observers didSet and willSet in Swift 4

Go to the profile of Onyekachi Ezeoke
Onyekachi Ezeoke

In this article, we will look into swift property observers. According to Apple’s 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 .

Lets have a look at the code snippet below to help us have a better understanding of how property observers willSet and didSet works.

Property observers are declared as a variable and not as constants because it is only a mutable property that can be tracked by property observers. Hence, property observers are declared with var and not the let keyword.

A property with observers on it when declared should have initial value assigned to it. This actually makes the difference between computed properties and property observers. Computed properties returns a value computed from other variable or properties and does not store the value in memory. Hence, to place observers on a property, you need to set the property to an initial value of a particular type. This value could be optional type or any other type.

One thing to note is that willSet and didSet will never get called on setting the initial value of the property. It will only get called whenever you set the property by assigning a new value to it. It will always get called even if you assign the same value to it multiple times.

willSet and didSet both have a default parameters newValue and oldValue. You are free to choose a custom parameter name of your choice as shown in the code above. These parameters are constants, hence you cannot mutate their values. Also note that in didSet, you can access the oldValue parameter and also the property whose value is already set.

Right now, lets explain what happens in the code above. We defined a struct Person with two stored properties name and age. And by placing our observer on the person property of type Person, we made it to be of optional type; meaning that the initial value of the person property is nil.

When the above code snippet is executed, the code in the viewDidLoad will get executed as can be seen in the screenshot below:

As can be seen from the screenshot above, the code in willSet will get called first before the person property is set. didSet will get called immediately when the person property is already set. That is why we could access the person property in didSet which is not possible in willSet.

From the code also, you can see that I used a custom parameter name in willSet observer; you are free to override the default parameter name with your own custom parameter name if you wish.

One more thing to note about property observers is this: property observers cannot be used on lazy variable because lazy variable get properly initialised and assigned to memory only when they are called in your program. Example is shown below:

lazy var name = "John"
print("My name is \(name)")

The variable name will only get properly initialised and assigned memory only when it has been called in the print statement above.

That defeats the purpose of a property observers because a property with observers on it need to have initial value. This will enable it track changes whenever they is change in value of the property.

The need for property observers arises when you have to keep a track on a property to determine when the value changes in order to perform some logic. So, instead of having some functions that checks the value of the property to perform some action, you can abstract that into the willSet and have it perform the logic when the value is set to the value you want.

I believe you now have a better understanding of how property observers in Swift works after reading through this article. Thanks for reading and feel free to raise any comment or questions below and I will have them answered.

The Andela Way
Never miss a story from The Andela Way, when you sign up for Medium. Learn more
Never miss a story from The Andela Way

Categories

  • Home
  • Development
  • Devops
  • People
  • Agile

Uncovering the mysteries of Swift property observers

Lammert Westerhoff
by Lammert Westerhoff
post-dateDecember 23rd, 2015
comments no comments

One of the cool features of Swift are property observers, perhaps better known as the willSet and didSet. Everyone programming in Swift must have used them. Some people more than others. And some people might use them a little bit too much, changing many of them together (me sometimes included). But it’s not always completely obvious when they are called. Especially when dealing with struct, because structs can be a bit odd. Let’s dive into some situations and see what happens.

Assignment

The most obvious situation in which didSet (and willSet) gets called is by simply assigning a variable. Imagine the following struct:

1
2
3
4
struct Person
    var name: String
    var age: Int

And some other code, like a view controller that is using it in a variable with a property observer.

1
2
3
4
5
6
7
8
9
10
11
class MyViewController: UIViewController
    var person: Person!
        didSet
            print("Person got set to ‘(person.name)’ with age (person.age)")
        
    
 
    override func viewDidLoad()
        person = Person(name: "Bob", age: 20)
    

As you would expect, the code in didSet will be executed when the view did load and the following is printed to the console:

1
Person got set to ‘Bob’ with age 20

Initialization

This one is also pretty clear and you probably already know about it: property observers are not executed then the variable is assigned during initialization.

1
2
3
4
5
var person = Person (name: “Bob”, age: 20)
        didSet
            print(“Person got set to ‘(person.name)’ with age (person.age)”)
        
    

This doesn’t print anything to the console. Also if you would assign person in the init function instead the willSet will not get called.

Modifying structs

A thing less known is that property observers are also executed when you change the member values of structs without (re)assigning the entire struct. The following sample illustrates this.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class ViewController: UIViewController
 
    var person = Person (name: “Bob”, age: 20)
        didSet
            print(“Person got set to ‘(person.name)’ with age (person.age)”)
        
    
 
    override func viewDidLoad()
        person.name = “Mike”
        person.age = 30
    
 

In this sample we never reassign the person in our viewDidLoad function but by changing the name and age, the willSet still gets executed twice and we get as output:

1
2
Person got set to ‘Mike’ with age 20
Person got set to ‘Mike’ with age 30

Mutating functions

The same that applies to changing values of a struct also applies to mutating struct functions. Calling such a function always results in the property observers being called once. It does not matter if you replace the entire struct (by assigning self), change multiple member values or don’t change anything at all.

1
2
3
4
5
6
7
8
9
10
struct Person
    var name: String
    var age: Int
 
    mutating func incrementAge()
        if age < 100
            age++
        
    

Here we added a mutating function that increments the age as long as the age is lower than 100.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class ViewController: UIViewController
 
    var person = Person (name: “Bob”, age: 98)
        didSet
            print(“Person got set to ‘(person.name)’ with age (person.age)”)
        
    
 
    override func viewDidLoad()
        person.incrementAge()
        person.incrementAge()
        person.incrementAge()
        person.incrementAge()
    
 

Our willSet is called 4 times, even though the last two times nothing has changed.

1
2
3
4
Person got set to ‘Bob’ with age 99
Person got set to ‘Bob’ with age 100
Person got set to ‘Bob’ with age 100
Person got set to ‘Bob’ with age 100

Changes inside property observers

It is also possible to make changes to the variable inside its own property observers. You can reassign the entire variable, change its values or call mutating functions on it. When you do that from inside a property observer, the property observers do not trigger since that would most likely cause an endless loop. Keep in mind that changing something in willSet will be without effect since your change will be overwritten by that value that was being set originally (this gives a nice warning in Xcode as well).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class ViewController: UIViewController
 
    var person = Person (name: “Bob”, age: 98)
        didSet
            print(“Person got set to ‘(person.name)’ with age (person.age)”)
            if person.name != oldValue.name
                person.age = 0
                print(“Person ‘(person.name)’ age has been set to 0”)
            
        
    
 
    override func viewDidLoad()
        person.name = “Mike”
    
 

Why it matters

So why does all this matter so much you might think. Well, you might have to rethink what kind of logic you put into your property observers and which you put outside. And all this applies to Arrays and Dictionaries as well, because they are also structs. Let’s say you have an array of numbers that can change and each time it changes you want to update your UI. But you also want to sort the numbers. The following code might look fine to you at first:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class ViewController: UIViewController
 
    var numbers: [Int] = []
        didSet
            updateUI()
        
    
 
    override func viewDidLoad()
        refreshNumbers()
    
 
    func refreshNumbers()
        numbers = [random() % 10, random() % 10, random() % 10, random() % 10]
        numbers.sortInPlace()
    
 
    func updateUI()
        print(“UI: (numbers)”)
    
 

Every time numbers changes, the UI will be updated. But since sortInPlace will also trigger the property observer, the UI gets updated twice:

1
2
UI: [3, 6, 7, 5]
UI: [3, 5, 6, 7]

So we should really put sortInPlace inside willSet right before we call updateUI.


Shares
  • 1

Previous post

Security is maturing in the Docker ecosystem

Next post

Interpreting Scala in the Browser

Leave a Reply Cancel reply

  • 1

Share This

  • Facebook

  • Twitter

  • LinkedIn

  • Google+

  • Hacker News