avatar

Alex E. Fish

iOS Developer in London, rambling about Objective-C, iOS Development and anything related.

If you would like to get in touch, feel free to email me or @ me on twitter.


Understanding and creating delegates in Objective-C

What the deuce is delegation?

Delegation is a powerful tool in a developers arsenal, i see delegation as a clean and simple way of connecting objects and helping them to communicate with other. In other words, delegation is a dating service for Objective-C objects.

If that makes no sense to you, which is likely, Apple puts it a lot better:

Delegation is a simple and powerful pattern in which one object in a program acts on behalf of, or in coordination with, another object. The delegating object keeps a reference to the other object—the delegate—and at the appropriate time sends a message to it. The message informs the delegate of an event that the delegating object is about to handle or has just handled. The delegate may respond to the message by updating the appearance or state of itself or other objects in the application, and in some cases it can return a value that affects how an impending event is handled. The main value of delegation is that it allows you to easily customize the behavior of several objects in one central object.

Still make no sense to you? Let me try and put this into plain english for you and give you a real life comparison to delegates in action..

Let's say we have two objects, Brain and Beer Bottle, Brain is the object we use to manage the entire Body application, it handles all of the important tasks such as poop, eat, drink, sleep etc. Beer Bottle is attached to body but it doesn't know what Brain is thinking, likewise, Brain has no idea what Beer Bottle is thinking.

Brain is using Beer Bottle's attributes to satisfy itself while it's watching TV, but the problem is that brain is so distracted by the tv that it can't pay attention to when beer is going to run out. This could all end in disaster, Brain needs to know when beer is empty so that it send body to the fridge and initialize another instance of Beer Bottle.

Brain can use the drink function to lower Beer Bottles liquid variable, but once liquid reaches 0, Brain needs to know about it, this is where delegates come into action, we can use a Beer Bottle Delegate. Brain can listen out for the Beer Bottle Delegate telling brain that the bottle is empty, all we need to do is simply tell Brain to listen out for Beer Bottle telling it's delegate that is empty and Brain can react to it. This well thought out and illustrated diagram shows all of this in action:

image

Alright, i get it now, but how do i use them?

Using the existing delegates is easy, take this code for example, it simply tells the current class that it needs to listen out for the UIActionSheetDelegate so that we can handle button clicks on an action sheet.

- (void)viewDidLoad { 

  [super viewDidLoad];

  UIActionSheet *actionSheet = [[UIActionSheet alloc]
          initWithTitle:@"Delegate Example"
          delegate:self // telling this class to implement UIActionSheetDelegate
          cancelButtonTitle:@"Cancel"
          destructiveButtonTitle:@"Destructive Button"
          otherButtonTitles:@"Other Button",nil

  [actionSheet showInView:self.view];

  [actionSheet release];
}

Our action sheet will simply show when the view loads, and this is how we handle the delegate so that we can do something when a button is clicked, it's easy..

- (void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
  NSLog(@"hello world!");
}

Looking good so far, but hold up one second, don't get carried away. We still need to make one little change to our code, currently we have told our class to implement the UIActionSheetDelegate by using delegate:self. But we forgot to tell our class to implement the UIActionSheetDelegate protocol so that it knows which functions are available to it! How do we do that i hear you cry? it's also easy, head to your .h file and simply do the following:

@interface DelegateExampleViewController : UIViewController <UIActionSheetDelegate>
{

}

For the not so eagle eyed, UIActionSheetDelegate is what has been added.

Awesome! But how do i create my own custom delegates for my classes?

Creating your own custom delegates is also pretty easy once you know how, i could try and explain it in text, but you might fall asleep so i will let the code do the talking. I've created a custom class for the sake of this example which will implement our custom delegate. Our delegate will simply send a message to it's owner saying hello.

Let's start with the header file of our custom class:

//
//
//  CustomClass.h
//  DelegateExample
//
//  Created by Alex Fish on 22/06/2011.
//  Copyright 2011 Alex E Fish. All rights reserved.
//



#import 

// declare our class
@class CustomClass;

// define the protocol for the delegate
@protocol CustomClassDelegate 

// define protocol functions that can be used in any class using this delegate
-(void)sayHello:(CustomClass *)customClass;

@end

@interface CustomClass : NSObject {

}

// define delegate property
@property (nonatomic, assign) id  delegate;

// define public functions
-(void)helloDelegate;

@end

Not so scary huh! and now let's look at the .m file i have also created:

//
//
//  CustomClass.m
//  DelegateExample
//
//  Created by Alex Fish on 22/06/2011.
//  Copyright 2011 Alex E Fish. All rights reserved.
//

#import "CustomClass.h"

@implementation CustomClass

@synthesize delegate;

-(id)init {

    self = [super init];

    return self;

}

-(void)helloDelegate {
    // send message the message to the delegate!
    [delegate sayHello:self];
}

-(void)dealloc {
    [super dealloc];
}

@end

It's as simple as that, now all we need to do is alter our view controller to implement the new delegate protocol we just created. It works exactly the same as  implementing UIActionSheetDelegate shown earlier on, sweet. Let's edit our example from earlier to implement our new delegate..

//
//  DelegateExampleViewController.h
//  DelegateExample
//
//  Created by Alex Fish on 22/06/2011.
//  Copyright 2011 Alex E Fish. All rights reserved.
//

#import <UIKit/UIKit.h>
// import our custom class
#import "CustomClass.h"

@interface DelegateExampleViewController : UIViewController <CustomClassDelegate> {

}

@end

Stick with me, we are almost there, finally in our view controllers .m file we simply init our custom class and force the delegate to send us a message:

CustomClass *custom = [[CustomClass alloc] init];
// assign delegate
custom.delegate = self;
[custom helloDelegate];
[custom release];

Now that everything is in place it's just a case of implementing our newly created custom delegate function (also in the view controllers .m file)

-(void)sayHello:(CustomClass *)customClass {
    NSLog(@"Hiya!");
}

That's it! As it may be hard to connect the dots via a blog post you can also download the full source code here to have a play/break and expand on it if needs be:

Download Source

I have no idea what you just said

If this is all going in one ear and out of the other, don't feel stupid, maybe you just need to hear it from someone else, here are some reading materials which may be easier to understand,

Wiki Stack Overflow Apple.