callbacks in swift

https://medium.cobeisfresh.com/why-you-shouldn-t-use-delegates-in-swift-7ef808a7f16b

CallBackSwift demo

Using callbacks for delegation

Callbacks are similar in function to the delegate pattern. They do the same thing: letting other objects know when something happened, and passing data around.

What differentiates them from the delegate pattern, is that instead of passing a reference to yourself, you are passing a function. Functions are first class citizens in Swift, so there’s no reason why you wouldn’t have a property that is a function!

MyClass now has a myFunction property that it can call and anyone can set (since properties are internal by default in Swift). This is the basic idea of using callbacks instead of delegation. Here’s the same example as before but with callbacks instead of a delegate:

1) we declare a class called NetworkService

2) We create a function type, called onComplete, that takes in a parameter of String type and returns Void. We make it into an optional so that we can take advantage of Optional Chaining, where we can query the reference. If its valid, great. If its nil, it would return nil and will not crash.

3) We create a function called fetchDataFromUrl that simulates getting data from a server by using sleep. After 2 seconds, granted something came back, we call our callback function property. However! Note here that our onComplete is defaulted to nil. Hence if we call onComplete in fetchDataFromUrl, it will query the nil and get nil back. Nothing will happen. In order for something to happen, we need to implement the onComplete optional function. You can implement onComplete in NetworkService initializer or externally since our onComplete is public.

a) Hence, usually, we will instantiate an object of our class. We have a reference to that object called service.
b) We then declare the callback definition for onComplete.
c) Finally, we call fetchDataFromUrl. After it runs through the function implementation, it calls the onComplete function as defined in b)

Another way to use callbacks – Data has changed!

1) as always, declare your callback. This time, we’re declaring the function type as having a parameter of “an array of String”, and returns void. Let’s call this property onUsernamesChanged

2) implement an init for our class, and define the definition for our callback. Since our callback’s function type has a parameter of an array of String, we use names as an identifier for that parameter.

3) Then, we simply use it in didSet.

Thus, another great way to use callbacks is when you want to get notified data has been changed.

Full Source Code

So why are callbacks better?

Decoupling

Delegates lead to pretty decoupled code. It doesn’t matter to the NetworkService who its delegate is, as long as they implement the protocol.

However, the delegate has to implement the protocol, and if you’re using Swift instead of @objc protocols, the delegate has to implement every method in the protocol. (since there’s no optional protocol conformance)

When using callbacks, on the other hand, the NetworkService doesn’t even need to have a delegate object to call methods on, nor does it know anything about who’s implementing those methods. All it cares about is when to call those methods. Also, not all of the methods need to be implemented.

Multiple delegation

What if you want to notify a ViewController when a request finishes, but maybe also a some sort of logger class, and some sort of analytics class.
With delegates, you would have to have an array of delegates, or three different delegate properties that might even have different protocols! (I’ll be the first to admit I’ve done this)

With callbacks, however, you could define an array of functions (I love Swift) and call each of those when something’s done. There’s no need to have a bunch of different objects and protocols risking retain cycles and writing boilerplate code.

Clearer separation of concerns

The way I see the difference between delegates and callbacks is that with delegates, the NetworkService is telling the delegate “Hey, I’ve changed.” With callbacks, the delegate is observing the NetworkService.
In reality, the difference is minimal, but thinking in the latter way helps prevent anti-patterns often found with delegation, like making the NetworkService transform results for presentation, which should not be its job!

Easier testing!
Ever felt like your codebase is twice as big with unit tests, because you have to mock every protocol, including all of the delegates in your app?
With callbacks, not only do you not have to mock any delegates, but it lets use use whatever callback you want in each test!
In one test, you might test if the callback gets called, then in another you might test if it’s called with the right results. And none of those require a complicated mocked delegate with someFuncDidGetCalled booleans and similar properties.