Using Swift Closures as an Alternative to Delegates

As iOS developers, we tend to use a lot of delegates, sometimes even abuse of these poor little fellas. But, what else can we use? Right?

We know a few other options, but they might feel awkward or a bit of an overkill, depending on what we want to accomplish.

Real World Example

If you’ve been programming in iOS before the introduction of the UIAlertController (iOS 8), you probably used its predecessor alert, UIAlertView. One of the most noticeable changes between these two alerts is the way they interact with their caller. TheUIAlertView notified the view controller about the button events using delegates, while the UIAlertController uses a closure of type ((UIAlertAction) -> Void)?. In my opinion, this change was a great improvement, which provides developers a cleaner way to implement the alert.

In this tutorial, we will create a simple “note taking” (almost useless) app and we will be using the closure pattern as an alternative to the frequently used, almost abused delegate pattern.

What you’ll need for this tutorial

  • Xcode 8
  • Swift 3
  • A bit of experience working iOS
  • High level understanding of swift optionals

Let’s Create Our Project

Create a new Xcode project.

I will name it tutorial_closures.

Command + n to add a new file. This file will be a subclass of an UIViewController .

and call it SecondViewController

Now we need to go to the storyboard and add a new UIViewController, change the custom class on the “Identity Inspector” to SecondViewController and set the“Storyboard ID” to secondViewController.

Awesome!

We now have our main project all set up.

What we’ll Build

Now that we have our project all set, let’s discuss a bit what we’ll be doing.

The project will have two views.

The first view controller(ViewController) will contain a UILabel and a UIButton.

  • The button will present the SecondViewController
  • The label text will be updated from the SecondViewController

The second view controller (SecondViewController) will contain a UITextField and twoUIButton (one to cancel and the other one to update ViewController label).

  • The text field will get the input from the user
  • The button will dismiss the current view controller
  • The switch will notify theViewController if the text from the text field on SecondViewController should update the label

Ok, that’s enough. Let’s start building this!

We’ll start by adding the UILabel and the UIButton to ViewController by adding the following code on top of the viewDidLoad() method.

Now lets add some layout constraints so the UILabel and the UIButton.

Create a new private method call addConstraints as follow:

Now, override the viewDidLoad method, and add the UILabel, the UIButton and the method we just created.

Great! Now let’s add a function to present the SecondViewController .

Awesome!

By now, your ViewController should look like this:

Now let’s run our project. You should see something exactly like this.

Awesome! Is not a pretty design, but it’ll work.

Now, this is our SecondViewController:

As you can see above, I added a few controls, the UITextField and twoUIButton.

Also, added two methods, cancel() and update(). The cancel() will dismissSecondViewController and update() will notify the caller about the action. Is important to notice that all update() method logic will be handled from the caller (in this scenario the ViewController).

But, what the heck is the buttonAction variable type?

The buttonAction variable is of type ((String?) -> ())? meaning the variable is a function (just like blocks in Objective-C). This is possible in swift because functions are first class citizens (often call first class objects). But don’t worry, in order to use them you just need to understand what they can do, how to create one and how to use them.

Let’s discuss each part of our buttonAction type: ((String?) -> ())?. To make it very clear, lets identify each part of it.

  • String?: this means that buttonAction can pass on an optional String (can have a string or be nil).
  • ->: identifies the “arguments” and what is the “returned” (just like functions). We’ll only work with the first part (the arguments).
  • (): this is equivalent to Void. It just says that nothing is expected.

Is important to notice that ((String?) -> ())? is optional, therefore ViewController not necessarily needs to implement the buttonAction variable. In case the variable is not implemented (buttonAction == nil) , the SecondViewController will only be dismissed.

Great! Now, let’s use this pattern to pass information from SecondViewController to ViewController.

Implementing Swift Closures to Pass Information from One ViewController to Another

Let’s implement the buttonAction variable on the ViewController. Add the following code on the ShowViewController(sender: UIButton) method just on top of the present(...) line.

secondViewController.buttonAction = {(text) -> () in
textLabel.text = text
return secondViewController.dismiss(animated: true, completion: nil)
}

If you try to run your code now, you should get an error like this one:

This means that we need to add the Objective-C extremely used self on our textLabel variable.

But… why? is not required anywhere else on the ViewController.
Right, is not required anywhere else on the ViewController, but we are now inside our closure declaration, and inside closures you need to use the self identifier.
OK…
Great!

By now the error must have disappear and you should be able to run the project and test everything you just did.

Coming back to our buttonAction, as we mention before, it is a closure, and closures are like functions.

So, we just declare the variable to a function with a variable text and a return value of type (), which is the same as Void.

Conclusion

Most of the time IOS programmers over use delegates since they don’t like very much the Objectivve-C block syntax (not my case, I used to loved that weird syntax). This article demonstrated that it is possible to use a closure to pass information from one view controller to another. This provides iOS developers a viable alternative to those good ol’ Delegates.

— — — — — — — —

We just used a closure to pass information from one view controller to another. As iOS developers (and if you are just coming from Objective-C), we sometimes used the Delegate pattern a lot.

Most of the time it was because some people didn’t like very much the Objective-C block syntax (not my case, I used to loved that weird syntax).

Now, with Swift closures we can let aside those good ol’ Delegates.

Download project