Understanding Delegates

McCallumDev
7 min readMay 29, 2019

--

A guide to help you (and me) simplify and understand delegates in Swift.

So what are delegates?

It’s best to think of a delegate as a method in which we can pass information between one object and another. In our case, from one view controller to another.

In this simple app, I have 2 View Controllers, which we will call BaseScreenViewController: (Screen 1) and a SelectSideViewController: (Screen 2)

Screen 1
Screen 2

How you style these or what theme you use is up to you, for now I’ll keep it simple and short. For this demonstration I have used 2 football teams.

Pseudo-Code

Let’s think about what we want this app to do. The user will click the “Choose a side” button on screen 1, Screen 2 will be presented offering the user 2 choices (choose wisely!) and then depending on which side the user chooses, Our original screen (Screen 1) will change to represent the users choice. For example, the users selects Real Madrid:

Screen 1 (Madrid Style)

Basic Set Up

For this project we need some basic set up. Start by creating 2 View Controllers and their Cocoa Touch Classes. I’m going to assume if you are researching delegates, this is something you are already comfortable with:

Be sure to set the class of each view controller and for the SelectSideViewController we will need to add a unique storyboardID which will act as an identifier.

BaseScreenViewController:

SelectSideViewController:

BaseScreenViewController

Below is our BaseScreenViewController file. I’ve added outlets for our image view (mainImageView), the choose button (chooseButton) and the label (clubLabel), as all of these values will change depending on which side the user selects. We also need to create an IBAction to instantiate (which is just a fancy way of saying create an instance of) our SelectSideViewController when the user taps the “choose a side” UIButton and then present it to the user, I’ve named this function “chooseSideTapped”.

(I’ve also added some styling to the chooseButton within the viewDidLoad to make it look a bit nicer 👍)

class BaseScreenViewController: UIViewController {
@IBOutlet weak var mainImageView: UIImageView!@IBOutlet weak var chooseButton: UIButton!@IBOutlet weak var clubLabel: UILabel!override func viewDidLoad() {super.viewDidLoad()chooseButton.layer.cornerRadius = chooseButton.frame.height/2}@IBAction func chooseSideTapped(_ sender: UIButton) {}}

Great! So now we have the basic set up of our base screen, Inside the chooseSideTapped function lets go ahead and add the code to instantiate and present our Screen 2:

@IBAction func chooseSideTapped(_ sender: UIButton) {let selectionVC =  storyboard?.instantiateViewController(withIdentifier: "SelectSideViewController") as! SelectSideViewControllerpresent(selectionVC, animated: true, completion: nil)}

In the code above we have created an instance of SelectSideViewController using our identifier and class and stored it in a constant called “selectionVC”. Next, we the use the present method to present this to the screen with some nice animation to boot.

SelectSideViewController

Now that we have a way of viewing our Screen 2, let’s have a look at the basic set up required for Screen 2:

class SelectSideViewController: UIViewController {@IBAction func barcaSelectedTapped(_ sender: Any) {  dismiss(animated: true, completion: nil)}@IBAction func realSelectedTapped(_ sender: Any) {  dismiss(animated: true, completion: nil)}}

To begin with, all this file requires is 2 actions for each of the buttons (with relevant images selected in the attributes editor), each containing a dismiss method. I have named these functions “barcaSelectedTapped” and “realSelectedTapped”. All this will do when tapped is pop the current view (Screen 2) off of the screen and return us to the previous view (Screen 1). Give it a try!

Delegate Analogy

The way I learned how to understand delegates was to imagine a Boss/Employee relationship. A boss wants to give a set of instructions to an employee and have the employee perform their duties. In our example Screen 2 is going to play the roll of BOSS and Screen 1 will be our new intern EMPLOYEE. the BOSS screen knows everything that the EMPLOYEE screen needs to do, in our case, change the badge, message and background colour to represent the choice our user has made.

Protocol (instructions)

The first thing we want to do is create a set of instructions that we are going to give the the EMPLOYEE. We do this using whats called a protocol. A protocol can have as little or as my instructions as necessary, for now all we need is 1 set of commands. Go ahead and add this code to your BOSS screen, right above your SelectSideViewController class:

protocol SideSelectedDelegate {  func choiceMade(badge: UIImage, message: String, color: UIColor)}

Essentially what this code is saying is, if you use this protocol, then you MUST follow these instructions, you MUST have this function, with these parameters. Sounds very BOSSy, right?

The Delegate (EMPLOYEE)

Next we need to have our EMPLOYEE act as the delegate and perform these instructions, whenever they are given. We do so as follows:

On the BOSS screen, we create a delegate:

var selectedDelegate: SideSelectedDelegate!

add this to the top of your SelectSideViewController class. Next, we need to tell the BOSS screen that the EMPLOYEE screen will act as the delegate. To do this, on your BaseScreenViewController file, update the “chooseSideTapped” function to look like this:

@IBAction func chooseSideTapped(_ sender: UIButton) {let selectionVC = storyboard?.instantiateViewController(withIdentifier: "SelectSideViewController") as! SelectSideViewControllerselectionVC.selectedDelegate = selfpresent(selectionVC, animated: true, completion: nil)}

What this extra line of code is saying is, “Hey, you have a delegate called selectedDelegate, that’s me! i’ll act as the delegate and perform what ever task is given to me”. At this point, if you are following along, you will probably get an error in your code, this is becasuse we have said “Hey, I will follow your protocol”, but right now we aren’t following protocol, because we don’t have a choiceMade() function anywhere on our EMPLOYEE screen. What a rebel. Let’s add that, at the bottom of your EMPLOYEE Screen, let’s follow protocol. Add an extension under your code:

extension BaseScreenViewController: SideSelectedDelegate {// Let's follow protocolfunc choiceMade(player: UIImage, message: String, color: UIColor) {  mainImageView.image = player  clubLabel.text = message  view.backgroundColor = color// We can also use this function to change the text of the chooseButton, as we know as soon as this function is used, a side has been selected  chooseButton.setTitle("Change Side",for: .normal)}}

We are now acting as the delegate and ready to perform the task set to us by the BOSS, however, our BOSS hasn’t yet given us the correct parameters to use for our “choiceMade” function. So let’s head back over to our BOSS screen and do that now.

We want to give a different set of parameters depending on which button the user chooses, we can do that using our IBActions we created earlier. Go ahead and update them to look like this:

@IBAction func barcaSelectedTapped(_ sender: Any) {selectedDelegate.choiceMade(badge:  imageLiteral(resourceName: "barca"), message: "Mes que un club", color: .red)dismiss(animated: true, completion: nil)}@IBAction func realSelectedTapped(_ sender: Any) {selectedDelegate.choiceMade(badge:  imageLiteral(resourceName: "real2"), message: "Hala Madrid", color: .blue)dismiss(animated: true, completion: nil)}

For each function, we are selecting the selectionDelegate, conforming to protocol and sending the instructions (Parameters) for the EMPLOYEE screen to execute.

The results should appear as follows:

Screen 1 (Barca Style)
Screen 2 (Madrid Style)

Delegates can be tricky to understand at first, but hopefully this blog has helped simplify it a bit more for you. Play around with it, add some instructions to follow an be creative.

Full code:

EMPLOYEE SCREEN, Screen 1, BaseScreenViewController

import UIKitclass BaseScreenViewController: UIViewController {@IBOutlet weak var mainImageView: UIImageView!@IBOutlet weak var chooseButton: UIButton!@IBOutlet weak var clubLabel: UILabel!override func viewDidLoad() {super.viewDidLoad()chooseButton.layer.cornerRadius = chooseButton.frame.height/2}@IBAction func chooseSideTapped(_ sender: UIButton) {let selectionVC = storyboard?.instantiateViewController(withIdentifier: "SelectSideViewController") as! SelectSideViewControllerselectionVC.selectedDelegate = selfpresent(selectionVC, animated: true, completion: nil)}}extension BaseScreenViewController: SideSelectedDelegate {func choiceMade(player: UIImage, message: String, color: UIColor) {mainImageView.image = playerclubLabel.text = messagechooseButton.setTitle("Change Side",for: .normal)view.backgroundColor = color}}

BOSS SCREEN, Screen 2, SelectSideViewController

import UIKitprotocol SideSelectedDelegate {func choiceMade(badge: UIImage, message: String, color: UIColor)}class SelectSideViewController: UIViewController {var selectedDelegate: SideSelectedDelegate!@IBAction func barcaSelectedTapped(_ sender: Any) {selectedDelegate.choiceMade(badge:  imageLiteral(resourceName: "barca"), message: "Mes que un club", color: .red)dismiss(animated: true, completion: nil)}@IBAction func realSelectedTapped(_ sender: Any) {selectedDelegate.choiceMade(badge:  imageLiteral(resourceName: "real2"), message: "Hala Madrid", color: .blue)dismiss(animated: true, completion: nil)}}

--

--