Delegates & callbacks in Swift (part 1)
Introduction:
CallBacks and Delegation are one of the often tools using by Swift developers. In this article, I try to explain the differences between them in point of view using and memory management.
What is delegation?
Delegation is a common design pattern where one class/struct delegates responsibility of implementing some functionality to another (the delegated class or struct). In order to make communication between the delegates and the delegated modules we use a kind of contract that we call Protocol.
- Protocol:
A protocol specifies initializers, properties, functions, subscripts required for a swift object type (class, struct, enum) conforming to the protocol.
For example, we can create a protocol called ShowResult that show result after make some arithmetics operations
public protocol ShowResult {
func show(value:Int)
}
Class, struct and enum can implements this protocol like this for example.
extension ViewController: ShowResult{
func show(value: Int) {
print(value)
}
}
Now, we understand protocol and how we can implement it using extension for example which is the more elegant way to do it. But what about delegation!!!
2. Delegation and protocol:
Imagine now that we have an UIViewController that want to make some mathematics operations but we don’t like to implement the mathematics functions inside our ViewController class. Maybe we should do this task in second class or struct .
Basically, we should have instance of the second class/struct in the ViewController class. This is our MyIntOperation instance. When, it finish work maybe it delegate the display to our ViewController class :). The ViewController object will observe event launched by the MyIntOperation object so we speak about one-to-one relationship.
class MyIntOperation {
weak var delegate: ShowResult?
func sum(firstNumber:Int, secondNumber:Int) {
// make arithmetic operation and delegate display to the ViewController
delegate?.show(value: firstNumber + secondNumber)
}
}
the delegate type is a protocol!! and every class/Struct that implement this protocol can do the call. Maybe when we make some Unit tests of the MyOperationClass we are not depend of the ViewController instance ;). we notice that delegation pattern respect the fifth principle of the SOLID because we infer only to abstractions ShowResult protocol not to concretions.
3. Memory management
Memory management is very important in any application. Swift uses Automatic References Counting (ARC) to keep track of the strong references to instances of classes and increase or decrease their reference count. ARC does not increase or decrease the reference count for value types like struct, enum because when assigned, these are copied.
3.1 Strong reference cycle:
The retain cycle is when two class depend on each other so we cannot release none of them but why?
the ViewController keep a reference of the MyIntOperation class and also this one keep a reference of the delegate which is simply a ViewController instance. That’s why ARC cannot release the ViewController when for example we go to a second view.
3.2 Weak reference:
When the ViewController is created, ARC increase reference count to 1. When MyIntOperation keep a reference to the ViewController ( delegate is simply a reference to it), ARC increment the count to 2 now. Imagine that we want to push a new ViewController, basically when we call the system call the Deinit method because the instance should be nil. But sadly, because we have a delegate reference kipped by the MyIntOperation object our retain count will be equal to one not zero and we cannot release our ViewController instance.
the solution is to declare the delegate weak so the retain count will not be increased and ARC can deallocate the ViewController instance.
Conclusion
In this first part, we studied delegation design pattern and the relation between it and memory management. The main idea is that this pattern is a communication type pattern which could be a source of retain cycles. It give a good opportunity to apply DI principle based on protocols. In the second part of this tutorial, we speak about closure call back and how we can observe event between objects using closure.