The Swift Swift Tutorial: Why Do We Need Delegates?

[Updated to Swift 2.0/iOS9 SJL 9/28/15]

A Note to readers: This post is out of date. Since Swift 3.0, iOS 10 and watchOS 3 have so many changes, I made a new post wth proper syntax, and a lot better illustrations. You can find that here on my site   or here on LinkedIn Pulse  

A reader in a comment recently asked a very good question: Why do we need delegates for UIViewControllers?  He thought Swift  made things easier, but this delegate stuff seems very complicated. Shouldn’t we be able to send a message or initializer between classes?

When I first learned iOS, I’ll admit it took me months to understand what happened with delegation. I found lots of confusing code and little explanation.  Moving away from my usually intermediate-level coding, I’m going to go back to basic computer science and break down that question in detail. I will be working in Swift for examples but the concepts should apply to every application developed in Objective-C, C++, Java, Python or any other Object-oriented language you can think of.

What is a Class?

While we use classes in object-oriented programming, it’s good to review what they actually are. A class is a collection of data, which we call properties, and actions we can do to those properties, which we call methods.

Properties and methods are either public or private. A public method is one that classes other than the defining class can see and can use. Private means that the property or method is only usable and visible within the defining class. Other classes cannot see or use it. In Swift the private keyword makes properties and methods private. Swift’s calculated properties feature is another way to make properties private. In Swift, there is also a default state which makes a method or class public to the current target, but not other targets.

We tend not to like other people messing with our insides, and that is a good programming practice too. In general, it is best to leave what is public by other classes to a necessary minimum. Keeping properties and methods private and not exposing all of our class is known as encapsulation.

Encapsulation allows us to make code as modular as Legos.

With good encapsulation, you classes should work like Legos.
With good encapsulation, you classes should work like Legos.

Just as a few stubs come out of an otherwise standard sized brick, only a few usable methods come out of a class. Then they can attach to a lot of other bricks.

What is  Model –  View – Controller  or MVC?

Model-View-Controller
Model-View-Controller

A term heard often  when working with Xcode, is MVC. MVC stands for Model-View-Controller. It is not an exclusive iOS or OS X term. It is a pattern of programming, a good organization of any program or application in a graphics-rich environment, and arguably any environment that interacts with the user. MVC separates the major parts of an application. First it seperates the data and the user interaction then adds an intermediary between them. Why is this important? You might write and publish an application for an iPhone, then decide an iPad version would be a good idea, then decide to make a OS X version. With MVC, you only change one part completely, the view and possibly some of the controller. The code handling your data never changes between the versions saving a lot of time and effort.

What is a Model?

Screenshot 2014-07-31 07.46.13
MVC – The Model, Our data

There are parts of our program that deal with information we want to process. A pizza ordering system has a list of data giving us information about each person’s order. There may be other links to that data with more data about each customer, and about each pizza. In a pizza ordering system this is our model: the collection of all the data we will use in our ordering system. It does not in any way interact with the user. It does not display anything or does it ask for input. It is just data. Here is an example of a model made from two classes:

class Pizza{
    var pizzaTopping:String
    var pizzaCrust:String
    var pizzaSize:Double
    var pizzaRadius:Double {
    get{
    return pizzaSize / 2.0 }
    }
    let pi = 3.1415926
    let crust = 0.1
    init(topping:String,crust:String,size:Double){
        pizzaTopping = topping
        pizzaCrust = crust
        pizzaSize = size
    }
    func howMuchCheese(height:Double) -> Double{
        return  (pizzaRadius * pi * (1.0 - crust )) * height
    }
}

class PizzaOrder{
    private var pizzaArray:[Pizza] = []
    private var tableNumber:[Int] = []
    func addOrder(pizza:Pizza, table:Int){
        pizzaArray.append(pizza)
        tableNumber.append(table)
    }
    func getOrder(index:Int) -> (Pizza,Int){
        return (pizzaArray[index],tableNumber[index])
    }
    func getPizzaOrder(index:Int) -> Pizza{
        return pizzaArray[index]
    }
    func changePizzaOrder(index:Int, newPizza:Pizza){
        pizzaArray[index] = newPizza
     }

}

This model is the data for a basic pizza ordering system. An instance of class PizzaOrder will be a list of pizzas of class Pizza, and a list of table numbers. There is a lot more methods I should add to describe the pizza ordering process, but like addOrder() and getOrder() any method is moving data only. There is no user input or output here. They might make calculations as we do in the howMuchCheese() method, but again there is no user interaction here.

What is a View?

MVC- The view
MVC- The view

Where all the user interaction happens is in the view. In Xcode, most people use Interface Builder either as a scene in a storyboard or a .xib file to build their views.  A developer can programmatically create a view class to hold the different controls.

The view for the pizza order app in a storyboard.
The view for the pizza order app in a storyboard.

As the model never interacts with the user,  the view never interacts directly with the data. The model doesn’t do much but sit there. It might respond to a user touch with feedback such as a notifying a method somewhere, a color change when a button gets tapped or a scrolling motion at times, but that is all it does. The view does contain a lot of properties and methods and that tell us the state of the view. We can change the appearance and behavior of the view through methods and properties. The view can tell the controller that there was a change in the view, such as a button getting pressed, or a character typed. it can’t do anything about it, but it can broadcast something.

What is a Controller?

MVC- The controller
MVC- The controller

The heart of MVC connects these two. Called the controller or view controller, it coordinates what happens in the model and what happens in the view. If a user presses a button on the view, the controller responds to that event. If that response means sending messages to the model, the view controller does that. If the response requires getting information from the model, the controller does that too. in Xcode, @IBOutlet and @IBAction connect Interface Builder files containing views to the view controller.

The key to MVC is communication. To be more accurate, the lack of communication. MVC takes encapsulation very seriously.  The view and the model never directly talk to each other. The controller can send messages to the view and the model. The view and controller may do an internal action to the message sent as a method call or it may return a value to the controller. The controller never directly changes anything in either the view or the model.

As an aside we need to talk about how Xcode with @synthesize and Swift coddles us. For true encapsulation, our properties should all be private and we should write two special methods: a getter to retrieve a value and a setter to change a value for every property. For example the property pizzaSize might be written this way:

private var pizzaSize:Double = 0.0
func setPizzaSize(size:Double){
    pizzaSize = size
}
func pizzaSize()->Double{
    return pizzaSize
}

We would have to do that for every property, which gets a bit tedious. Apple introduced @synthesize in Xcode 4.4 for Objective-C to automate this process. Instead of writing your setters and getters, all that was necessary was to add a statement in your implementation file

@synthesize pizzaSize

Xcode then generates the setter and getter behind the scenes for you. Later versions of Objective-C and Swift hide this completely and create the illusion you are directly modifying a property. You don’t need the setter or getter (though you can write your own) and in Swift @synthesize is not even in the language since it hides the setter and getter completely unless you specify it.

Why I mention this is the illusion of directly modifying properties in the view and model by the controller. It isn’t directly modifying anything. Behind the curtain are getter and setter methods. The model can not assign values in the controller. Then how do we assign values from the model to the controller? The model can return a value in a method, often a getter, called by the controller.

So to summarize, a view, a model and a controller cannot directly change a property in each other. A view and a model may not talk to each other at all. A view can tell the controller there is a change in the model. A controller can send messages in the form of method calls to the view and the model and get the responses back through that method.

MVC with Controller sending messages to View and Model.
MVC with Controller sending messages to View and Model.

How Does MVC Connect to Other MVC’s

What we’ve discussed so far is for only one scene in a much larger application. Suppose I have the following storyboard:

Two Scenes (view controllers) connected with a segue
Two Scenes (view controllers) connected with a segue

I have an Edit Pizza scene in my pizza order entry app. I need to send information to it to run properly and I would need to get information back. In the world of MVC, the controller does this. But we’ve a small problem: Data flows one-way from the calling controller to the new controller.

The Easy Direction

In Xcode we have what are known as segues. Segues are a convenience to point from one view controller to another. There are alternates to segues including initializing the new view controller from the old one directly. This is useful for popovers and modal views. When working with more complex navigation controllers segues keep track of some things that would become cumbersome to control ourselves in a simple way. When we move from one controller to the next, the segue tells the system to open this particular view controller, which then opens up a view and model. The model and view in the new MVC setup is different then the calling one. Apple includes a method prepareForSegue() which give us a chance to set values in the new view controller, and subsequently the new view controller’s view and model.

I might for example edit a pizza order. The user would give the order number, and the controller would ask the model for the pizza associated with that order. The model would return that order as an instance of Pizza and send that to a new view controller whose model is a single instance of pizza. Our prepareForSegue() for a navigation controller might look like this:

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!){
    if segue.identifier == "editOrder" {
        var vc = segue.destinationViewController as! EditPizzaViewController
        let orderNumber = Int(orderNumberText.text!)
        vc.pizza = pizzaOrder.getPizzaOrder(orderNumber)
        vc.orderNumber = orderNumber
    }
}

We first find if this is the correct segue in line 2. If so, we make the new view controller EditPizzaViewController. We get an order number from the text field in line 4. We set two properties, orderNumber, and the pizza which becomes the model for the new view controller. Everything moves nicely and when the Edit Pizza screen opens, everything looks good.

The Problem Direction

We can edit the information for the pizza easily enough in the new MVC. But when we press Done to send it back to the OrderPizzaViewController is when problems show up. By the rules of MVC, we need a method to return a value. Where in a called instance can we go back to the class calling it? With an encapsulated class we can’t. There is no way to send that revised model back to the original controller without breaking encapsulation or MVC. The new view controller does not know anything about the class that called it. We look stuck. If we try to make a reference directly to the calling controller, we may cause a reference loop that will kill our memory. Simply put, we can’t send things backwards.

This is the problem that delegates and protocols solve by being a little sneaky. Imagine another class, one that is really a skeleton of a class. This class contains only methods. It declares that certain methods are in this class, but never implements them. Generally known as abstract classes, in Swift they are protocols. We make a protocol class that has one method. That method is what you do when you are done in the EditPizzaViewController, and want to go back to the OrderPizzaViewController. It has a few parameters, things you want to pass back to the calling view controller.  So it might look like this:

protocol PizzaEditDelegate{
    func editPizzaDidFinish(pizza:Pizza,controller:EditPizzaViewController)
}

I passed back a pizza with changed properties, and I sent back my View Controller. It’s often good to send back the controller to the delegate. We most often use it for dismissing the controller, but sometimes it may have a property we need.

In our new view controller EditPizzaViewController, we make an instance of this protocol.

delegate:PizzaEditDelegate? = nil

Since we have a property of type PizzaEditDelegate, we can use the methods of the PizzaEditDelegate type, In our example, that is our method editPizzaDidFinish. We can stick that method call in a action for a Done button:

@IBAction func doneButtonPressed(sender:UIButton!){
    delegate!.editPizzaDidFinish(pizza, controller: self)
}

Since protocols are skeletons, it means any other class can adopt them. A class makes the protocol methods part of its own class with a stipulation. As soon as a protocol gets adopted, you need to flesh out the skeleton. The developer has to code the required methods in the adopted class’ code. We adopt a protocol by placing it after the name of the class and superclass,

class OrderPizzaViewController:UIViewController,PizzaEditDelegate

As soon as you do that, you will get a compiler error since the protocol’s method does not exist in the class. In the code for the adopting class, in our example OrderPizzaViewController, we would implement the method

func editPizzaDidFinish(pizza:Pizza, controller:EditPizzaViewController){
    let orderNumber = controller.orderNumber
    pizzaOrder.changePizzaOrder(orderNumber,newPizza: pizza)
    controller.navigationController!.popViewControllerAnimated(true)
}

We get the data back, place it where it belongs, and dismiss the newer controller taking the model and view with it using the controller parameter. While it i s good documentation to place all your passed values as parameters, inthis example, orderNumber comes from its property of controller. The pizza from the new view controller is now a parameter, something we can work with in our model self.pizza. I change our model via the original view controller calling a method of the model changePizzaOrder().

One more step. While back in the destination controller EditPizzaViewController I said the delegate was an instance of the protocol, I didn’t say where the delegate was. In prepareForSegue I add one more line vc.delegate = self saying the protocol is your controller

override func prepareForSegue(segue: UIStoryboardSegue!, sender: AnyObject!){
    if segue.identifier == "editOrder" {
        var vc = segue.destinationViewController as EditPizzaViewController
        let orderNumber = Int(orderNumberText.text!)
        vc.pizza = pizzaOrder.getPizzaOrder(orderNumber)
        vc.orderNumber = orderNumber
        vc.delegate = self
    }
}

When we tap Done, the method runs, it knows it is located in the calling controller, and calls it there where we added to the original class.The data is a parameter so the program can easily transfer into the controller and to the model. Delegates and protocols are bit sneaky but it works, and is one of the most important techniques when working with view controllers.

A diagram of how a delegate attaches to a adopted protocol.
A diagram of how a delegate attaches to a adopted protocol.

The original question asked why didn’t Swift make this simpler. As I hope I’ve shown here with a Swift context, it doesn’t matter what object oriented language you use. Delegates are part of the MVC pattern, which is a good programming practice.

46 thoughts on “The Swift Swift Tutorial: Why Do We Need Delegates?”

  1. Just stumbled upon your blog while looking for information about Swift and want to add that going reactive is a nice alternative you might consider. It simplifies things a lot (although it requires a mind shift).
    See
    http://peak.telecommunity.com/DevCenter/Trellis#model-view-controller-and-the-observer-pattern
    .NET: http://msdn.microsoft.com/en-us/data/gg577609
    Java: https://github.com/Netflix/RxJava
    JavaScript: https://baconjs.github.io/
    Cocoa: https://github.com/ReactiveCocoa/ReactiveCocoa

    Your tutorials are very well written and I think your readers might like a tutorial on how to use this on iOS (with or without Swift).

    1. Thanks !! You read my mind. That is actually on the schedule for sometime soon. I sorta fudged how the view communicates to the controller in this post, though a lot of it is notifications, plus a few features that look like notifications in Swift.

  2. Great Tutorial but i’m trying it out and the code does not work:

    I created this class “Pizza.swift”:
    ———————-Pizza.swift—————-
    import Foundation

    class Pizza{
    var pizzaTopping:String
    var pizzaCrust:String
    var pizzaSize:Double
    var pizzaRadius:Double {
    get{
    return pizzaSize / 2.0 }
    }
    let pi = 3.1415926
    let crust = 0.1
    init(topping:String,crust:String,size:Double){
    pizzaTopping = topping
    pizzaCrust = crust
    pizzaSize = size
    }
    func howMuchCheese(height:Double) -> Double{
    return (pizzaRadius * pi * (1.0 – crust )) * height
    }
    }

    class PizzaOrder{
    private var pizzaArray:[Pizza] = []
    private var tableNumber:[Int] = []
    func addOrder(pizza:Pizza, table:Int){
    pizzaArray.append(pizza)
    tableNumber.append(table)
    }
    func getOrder(index:Int) -> (Pizza,Int){
    return (pizzaArray[index],tableNumber[index])
    }
    func getPizzaOrder(index:Int) -> Pizza{
    return pizzaArray[index]
    }
    }
    ———————-PizzaController.swift——————-
    private var pizzaSize:Double = 0.0

    func setPizzaSize(size:Double){
    pizzaSize = size
    }

    func getPizzaSize() -> Double{
    return pizzaSize
    }
    ———————PizzaView.swift———-

    Can you please provide this code?

    Thanks

    SwCon

  3. Nicely explained :), It cleared my doubts regarding delegates to a great extent. Thanks a lot. Had been searching a lot about it but couldn’t find something so apt and precise. Thanks and please keep posting about other topics too.

    1. You are very welcome– thank you for the compleny. Right now it sems Autolayout and class sizes are my thing, but I find that is another area where a good explanation is necessary.

  4. “PizzaOrderViewController” and “PizzaDemoViewController” should be “OrderPizzaViewController”, you use 3 different names to indicate one view controller.

  5. “PizzaOrderViewController” and “PizzaDemoViewController” should be “OrderPizzaViewController”, you use 3 different names to indicate one view controller.

  6. I’m begginer with programming and I tried to figured out what’s the big deal with delegates. And after your quide my mind blowed up and now everything is so clear! Thanks!

    1. Segues keep track of where we are and a lot of background navigation information– particularly in navigation controllers. Segues are also linked to Interface builder, so it makes calling new scenes from the storyboard much easier. It is true that for modal controllers you don’t need a segue, but you should very rarely have more than one modal controller open for any length of time. you will, on the other hand have a lot of navigation controllers open. To keep those all straight, segues perform much of the work maintaining the navigation controller stack. Thirdly, overriding prepareforsegue is good communication and documentation of you code.

  7. thanks so much i was trying to understand how delegates work and you explained it very well before coming here i check at least 9 websites

  8. Thanks for the tutorial! When I press the ‘save’ button, however, it does not go back to the original view controller. I have read all the comments and my view is embedded in the navigation controller, in prepareForSegue i have vc.delegate = self, and all other troubleshooting methods don’t seem to help.
    –my question is, what changes the delegate? We set it to nil and then nothing (maybe saveColor or colorSelectionButton should?) seems to change it to anything else, so it doesn’t fall in the if statement
    if (delegate != nil) {…}

    1. I’d suggest you read this post very carefully, since it will answer your question me throughly than I can in a comment. Delegation is one of the most difficult ideas to wrap your head around, so read this post several times. The short answer to your question is the statement in a segue vc.delegate = self changes the delegate. I’ll quickly go through the process that a delegate works though if it helps:

      • There is protocol which defines your delegate in a controller which will need to send back a model to another controller, you add a method declaration without any code for a method didFinish(data) in this protocol.
      • You adopt this protocol in a starting controller. It mandates you write a method didFinish(data)
      • When the application runs, the application hits code which wants you to move from this controller to a new destination, which had that protocol
      • The application segues to a destination view controller which we call vc in the current controller in the prepare for segue:
      • If the segue is the correct one for this controller, the code sets vc.delegate to the current view controller before loading the destination
      • The destination loads and the user uses it.
      • When the user hits the done button in the application for that destination controller, the action associated with that button has code to run delegate.didFinish(data). delegate.didFinish(data) refers back to your initial few controller’s implemented delegate method and runs the code there. Since this code is happening in the initial view controller and not the destination view controller, you can set values from the parameter data to a variable in your initial controller.
      • If you included a parameter controller, in the delegate method, the delegate method dismisses the controller. If not, the code in the destination controller’s done action dismisses the controller
  9. I HAVE MENTIONED IN BLOCK LETTERS BELOW THE LINE I NEED EXPLANATION … locationmanager.delegate = self IN THAT WHAT DOES “.delegate” and assigning self mean? and what are we doing there?
    //
    // ViewController.swift
    // SpeedMap
    //
    // Created by Elton Menezes on 7/7/16.
    // Copyright © 2016 Menezes Elton. All rights reserved.
    //

    import UIKit
    import MapKit
    import CoreLocation
    class ViewController: UIViewController,CLLocationManagerDelegate,MKMapViewDelegate {

    @IBOutlet weak var myMap: MKMapView!
    @IBOutlet weak var speedLabel: UILabel!
    @IBOutlet weak var locationLabel: UILabel!

    var locationmanager = CLLocationManager() //referring to the class here
    var overlay = MKCircle() //referring to the class here

    var latDelta: CLLocationDegrees = 0.5
    var longDelta: CLLocationDegrees = 0.5

    override func viewDidLoad() {
    super.viewDidLoad()

    locationmanager.delegate = self (PLEASE EXPLAIN TO ME THIS LINE)
    locationmanager.desiredAccuracy = kCLLocationAccuracyBest//specifies the location accuracy
    locationmanager.requestWhenInUseAuthorization()//Asking the user for authorization
    locationmanager.startUpdatingLocation()

    speedLabel.text = “0 km/hr”
    locationLabel.text = “”

    myMap.delegate = self
    }

    func locationManager(manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {

    let myLocation: CLLocation = locations[0] as CLLocation

    let latitide: CLLocationDegrees = myLocation.coordinate.latitude
    let longitude: CLLocationDegrees = myLocation.coordinate.longitude

    let span: MKCoordinateSpan = MKCoordinateSpanMake(latDelta, longDelta)//Structure that defines area spanned by the map region so we need the zoom variables of latDelta and longDelta
    let location: CLLocationCoordinate2D = CLLocationCoordinate2DMake(latitide, longitude)

    let region: MKCoordinateRegion = MKCoordinateRegionMake(location, span)//defines which portion of the map to display
    myMap.setRegion(region, animated: true)//Keeps changing the region to be displayed

    let speed = Int(max(myLocation.speed, 0) * 3.6)

    speedLabel.text = “\(speed) km/hr”

    CLGeocoder().reverseGeocodeLocation(myLocation) { (placemarks:[CLPlacemark]?, error: NSError?) -> Void in

    if error == nil {

    let placemark = placemarks?.first//We would always get the first object which would give the updated location

    let subthoroughfare = placemark?.subThoroughfare != nil ? placemark?.subThoroughfare : “”
    let throughfare = placemark?.thoroughfare != nil ? placemark?.thoroughfare : “”
    let country = placemark?.country != nil ? placemark?.country : “”

    let location = “\(subthoroughfare!) \(throughfare) \(country)”

    self.locationLabel.text = location
    }
    }

    }

    @IBAction func zoomIn(sender: AnyObject) {
    }
    @IBOutlet weak var zoomOut: UIBarButtonItem!

    override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
    }

    }

  10. Shouldn’t this: “The controller can send messages to the view and the controller. The view and controller may do an internal action to the message sent as a method call or it may return a value to the controller.”

    rather read as that: “The controller can send messages to the view and the model. The view and model may do an internal action to the message sent as a method call or they may return a value to the controller.”?

  11. Great post, Steven! Thank you for taking the time to write it. I’m still trying to wrap my brain around this and I have a question for you. In ‘The Problem Direction’ you said, “The new view controller does not know anything about the class that called it. We look stuck.” and I understand that, but in ‘prepareForSegue’ we’re getting a reference to to view controller we’re going to segue to so therefore it knows something about the class it’s calling. Why doesn’t this knowledge violate the principles of MVC and encapsulation?

    1. First, just so you know, I just updated this with a new version:

      And now to your question. Let’s look at the line of importance in prepare(forSegue:)

      var vc = segue.destinationViewController as! EditPizzaViewController
      vc.pizza = pizzaOrder.getPizzaOrder(orderNumber)

      This gets a pointer to the destination controller vc then sets a property of vc named pizza, which the destination controller in turn sets its model of class Pizza.

      A controller can set or get properties from the classes it knows, i.e. that were instantiated within its code. A different way of describing MVC is that the job of the controller: Being in control of the model, view, and any other classes it calls, which usually is the controller of another MVC. It gets and sets the values of one class to another: Controllers are the transfer station with logic. It would break MVC to have this controller directly access another controller’s model, but it can instantiate another view controller and set the properties of the controller. That is what goes on in this prepare(forSegue:).

      You’ll find an even more barefaced example in this code for presenting a modal:

      let vc = EditPizzaViewController()
      vc.pizza = pizzaOrder.getPizzaOrder(orderNumber)
      present(vc, animated: true, completion: nil)
      

      As long as you change properties in vc only you are not breaking MVC. pizza is a property of vc, so you can move the pizza ordered from the current MVC to the destination MVC.The way this is all set up its actually difficult to break MVC. A shared model would break MVC, where two controllers control a single model. Two controllers talking to each other doesn’t break MVC.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s