CloseHomeAboutBlogContactCourse
Bob I’m an iOS instructor/blogger from S.Korea.July 14 • 5 min read • Edit

The Complete Understanding of Swift Delegate and Data Source

Pass data between view controllers and the behind scene.

Motivation

The delegate/data-source pattern exists everywhere within the iOS ecosystem. Most new students/developers simply copy & paste without knowing the behind implementation.

If you’ve wondered how UITableViewDataSource works, you might have come to the right place with BTD.

Introduction

First, the delegate design pattern is used to pass data or communicate between classes or structs. That’s it. The word “delegate” may come across confusing. I will try to use an analogy throughout the tutorial.

Your job is to pass data from FirstVC to SecondVC. Let us use the delegate pattern. First, you need to create a protocol that has a required method with a String parameter.

protocol FirstVCDelegate {
  func passData(data: String)
}

Second, create a class called, FirstVC.

class FirstVC {
 var delegate: FirstVCDelegate?
}

FirstVC has an optional property delegate whose type is FirstVCDelegate. The delegate property will be initialized by SecondVC later. Bear with me for a minute. You will see the magic.

If you aren’t comfortable with protocols, you may go grab some firepower from Intro to Protocol Oriented Programming and revisit.

Last, let us design SecondVC which conforms to FirstVCDelegate.

class SecondVC: FirstVCDelegate {
 func passData(data: String) {
  print("Something happened")
 }
}

Let us create the objects.

let firstVC = FirstVC()
let secondVC = SecondVC()

First, we’ve initialized two objects. If you remember correctly, the FirstVC class had an optional property called, delegate. Let us assign the optional property to secondVC.

firstVC.delegate = secondVC  // secondVC = delegate

Now, the magic happens. You are able to execute the passData method from FirstVC even though the passData method resides in SecondVC.

firstVC.delegate?.passData(data: "a bunch of contracts”)
// "Something happened"

Analogy

I often describe the delegator/delegate relationship analogous to that of CEO/secretary. delegate/secondVC is the secretary while delegator/firstVC is the CEO. The CEO may have a bunch of contracts and he/she simply tells the secretary to handle them by sending the documents.

firstVC.delegate?.passData(data: "a bunch of contracts”)

Now, let’s use the data passed by the CEO within SecondVC.

class SecondVC: FirstVCDelegate {
 func passData(data: String) {
  print("The CEO gave me \(data)")
 }
}

When the CEO calls the passData method, the secretary automatically calls the method and he/she may use the data a.k.a contacts given from the CEO as shown below.

firstVC.delegate?.passData(data: "a bunch of contracts”)
// "The CEO gave me a bunch of contracts"

Done. You’ve learned how to pass data from FirstVC to SecondVC using the delegate/delegator relationship.

Application

Knowing is not enough. Let us take a look at how the delegate pattern is used within the iOS ecosystem. If you’ve worked with UITableView, you’ve seen,

class BobViewController: UIViewController, UITableViewDelegate {
 override func viewDidLoad() {
  super.viewDidLoad()
  tableView.delegate = self
 }
}

In the code above, there are two objects. One is self which refers to the object of BobViewController and tableView. In this case, the CEO is tableView, and the secretary is self.

The CEO, tableView, may call, didSelectRowAtIndexPath. But, it rather tells the secretary to do something about it.

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
 print("The CEO gave me a bunch of stuff. I need to handle this")
}

There are all kinds of data from the parameters such as tableView, indexPath, and the secretary is able to use the “data” or information given from the CEO.

Let us move onto data source.

Custom Data Source

The delegate is used to send data from the CEO to the secretary. With data source, the secretary is able to talk back to the CEO.

Design Protocol

The protocol contains a method, passData. But, it returns a String value.

protocol FirstVCDelegate {
 func passData(data: String) -> String
}

Design CEO

class FirstVC {
 var dataFromSecretary: String?
 var delegate: FirstVCDelegate?
}

To store data received from the secretary, the CEO has dataFromSecretary.

Design Secretary

class SecondVC: FirstVCDelegate {
 func passData(data: String) -> String {
  print("The CEO gave me \(data)")
  return "Too much work"
 }
}

Now, the secretary talks back to the CEO when he/she hands over the contracts.

Create CEO and Secretary

let firstVC = FirstVC() // CEO: delegator
let secondVC = SecondVC() // Secretary: delegate

Now, assign the delegate.

firstVC.delegate = secondVC

Let us call the method.

firstVC.dataFromSecretary = firstVC.delegate?.passData(data: "a bunch of contracts") // "The CEO gave me a bunch of contracts"

As usual, the secretary complains by stating, “The CEO gave me a bunch of contracts”. But, the secretary returns a String “Too much work”.

print(firstVC.dataFromSecretary) // "Too much work"

Application

When you see, UITableViewDataSource, there is a required method, numberOfRowsInSection. But, similar to passData, the method must return Int.

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
 return 1996
}

In this case, self tells the number of rows to the tableView object. The CEO now receives the information and create its own custom UI design such as creating view objects and so on. We, developers, have no clue since the UIKit framework is not open sourced.

That’s it. Source Code

About Me

iOS Developer from South Korea. Feel free to follow my story on Instagram or get serious on LinkedIn