Swift — Observers
During my work on numerous apps, I’ve run into the need of detecting when my app goes from the background to foreground and vice versa.
Sometimes i want to save a state, or an image, or just change a text when the user decides to move the app into the background, on the other side, when the user moves the app into foreground (while it was in the background) I want to show some kind of view or notify the user that something is happening.
To achieve that kind of behaviour the great minds of Apple gave us the Observer
.
The Observer is a pattern in Swift, and it’s implemented in iOS with KVO (Key-Value observing).
An Observer
is an object that notifies when the state of another object changed.
An Observer
can be registered and deregistered by a subject (UIViewController for example), it’s important to register them so they can work, and let’s not forget to deregister to prevent memory leaks.
An object needs to subscribe to an Observer
to let the observer know it wants to be notified when changes take place.
What is KVO?
Before we dive into types and examples for observers i want to show and explain what is KVO (Key-Value observing).
In general term KVO is a programming pattern, we use it to notify objects about changes in their properties.
Important: you can only use KVO in objects that inherits NSObject
.
Let’s take a look at KVO example:
Here we define a new class Dog
(important , the Dog
class inherits NSObject
so it can use the KVO pattern), the object has a name with the word dynamic
, then we create a new object myDog
from the class Dog
.
Let’s continue so we can see how we can use the KVO pattern:
We define an observe on our new myDog
object, and print the new name, which means , when someones changes the name
property for myDog
the console will the change.
To test this we can do the following:
One we run the following code the console will print the following:
My new name is: Snowy
Foreground
To be able to detect when the app comes from the background into the foreground we need to register the following observer:
As we can see in the snippet above, we’re retrieving the default state of the NotificationCenter
and adding an Observer
.forName:
field here is important, the UIApplication.willEnterForegroundNotification
is a saved Swift phrase and is there to tell the system we would like to listen when the app goes to foreground.object:
field defines the object that sent the notification to this Observer
block.queue:
field defines the operation queue where the code in the closure will run, if the queue is set to nil
the code will run synchronously in the thread that posted this Observer
.
Another way to add this observer is:
selector:
the block of code that will run once the notification for this Observer
is sent.
The only difference in this snippet is that instead of having a closure and defining what to do as part of the Observer
declaration, we’re giving a selector
with our function, this selector is executed when the app enters foreground.
Background
As i mentioned before, sometimes we want to understand when the user moves the app to the background (by clicking the home button for example or swiping the screen up in notch devices).
The following code shows how to add the observer for listening when the app goes to the background.
Important: this is the exact same declaration as the foreground observer I mentioned before, the only difference is the forName:
field.
Here is another way to declare a background Observer
.
After registering our observers, they are ready to be used, they are currently listening and will let us know when the expected behaviour will take place (app moves to foreground or background).
Like I wrote at the beginning we must not forget to deregister the observers when we’re done using them, keeping the observers alive can cause memory leaks or other unexpected behaviour.
The following code deregister all observers from the current object:
The following code removes all the observers registered for the current object.
But what if we want to remove a specific observer, how do we do that?
First, we need to register the observer a bit differently and keep a reference to it.
We created an observer
of type NSObjectProtocol
and registered the foreground Observer
into it.
So now we hold reference to the Observer
, let’s see how can we release this Observer
only, the following code shows how we can deregister a single Observer
In the code above we can see how we can release a single Observer
and not all registered Observers
in that object.
A small suggestion, i usually release my Observer
in the deinit
function, this function is called when the object is released and not needed anymore.
Conclusion
There are many other observer types you can register into your app, in the following article I just showed two important and useful examples, you can even register your own Observer
.
It’s important to remember to deregister the observer when you’re done with it to prevent unexpected behaviour and memory leaks.
For further reading click here