Show Menu

Looking for an iOS Developer?

Submit your 30 day Job Listing for FREE

iOS development tutorial

Firstly, What is an Objective-C Delegate? Well.. An Objective-C delegate is just an object that has been assigned as a delegate of another. There’s no special process for creating them; you simply define a class that implements the delegate methods you’re interested in. (Though with delegates that use a formal protocol, you must declare your delegate to implement that protocol; see below.)

This post is an updated version of a previous post: Quick Tip: Create your own Objective-C Delegate Protocol and was taken from: SO

For example, suppose you have an NSWindow. If you’d like to implement its delegate’s windowDidMove: method, you could create a class like this:


@implementation MyClass
- (void)windowDidMove:(NSNotification*)notification { 
    // ... 
}
@end

Then you could create an instance of MyClass and assign it as the window’s delegate:


MyClass *myDelegate = [[MyClass alloc] init];
[window setDelegate: myDelegate];

On the NSWindow side, it probably has code similar to this to see if the delegate responds to the windowDidMove: message using respondsToSelector: and send it if appropriate.


if([[self delegate] respondsToSelector:@selector(windowDidMove:)]) {
    [[self delegate] windowDidMove:notification];
}

The delegate property itself is typically declared weak (in ARC) or assign (pre-ARC) to avoid retain loops, since the delegate of an object often holds a strong reference to that object. (For example, a view controller is often the delegate of a view it contains.)

To define your own delegates, you’ll have to declare their methods somewhere. There are two basic approaches, discussed in the Apple Docs on protocols:

1) An Informal Protocol

This can be done, as NSWindow does, in a category on NSObject. For example, continuing the example above, this is paraphrased from NSWindow.h:


@interface NSObject(NSWindowNotifications)
- (void)windowDidMove:(NSNotification *)notification;
// ... other methods here
@end

You would then use -respondsToSelector:, as described above, when calling this method. Delegates simply implement this method, and they’re done. This method is straight-forward and common in Apple’s libraries, but new code should use the more modern approach below.

2) A Formal Protocol

The newer option is to declare a formal protocol. The declaration would look like this:


@protocol NSWindowNotifications 
@optional
- (void)windowDidMove:(NSNotification *)notification;
// ... other methods here
@end

This is analogous to an interface or abstract base class, as it creates a special type for your delegate, NSWindowNotifications in this case. Delegate implementors would have to adopt this protocol:


@interface MyDelegate 
// ...
@end

And then implement the methods in the protocol. For methods declared in the protocol as @optional (like most delegate methods), you still need to check with -respondsToSelector: before calling a particular method on it. Apple recommends this method, because it is more precise, doesn’t mess with NSObject and can provide better tool support.

Speed Optimisations

Instead of checking whether a delegate responds to a selector every time we want to message it, you can cache that information when delegates are set. One very clean way to do this is to use a bitfield, as follows:


@protocol SomethingDelegate 
@optional
- (void)something:(id)something didFinishLoadingItem:(id)item;
- (void)something:(id)something didFailWithError:(NSError *)error;
@end

@interface Something : NSObject
@property (nonatomic, weak) id  delegate;
@end

@implementation Something {
  struct {
    unsigned int didFinishLoadingItem:1;
    unsigned int didFailWithError:1;
  } delegateRespondsTo;
}
@synthesize delegate;

- (void)setDelegate:(id )aDelegate {
  if (delegate != aDelegate) {
    delegate = aDelegate;

    delegateRespondsTo.didFinishLoadingItem = [delegate respondsToSelector:@selector(something:didFinishLoadingItem:)];
    delegateRespondsTo.didFailWithError = [delegate respondsToSelector:@selector(something:didFailWithError:)];
  }
}
@end

Then, in the body, we can check that our delegate handles messages by accessing our delegateRespondsTo struct, rather than by sending -respondsToSelector: over and over again.

Now taken from stack overflow, if you want a one minute answer, try this:

MyClass.h file should look like this (add delegate lines with comments!)


#import 

@class MyClass;             //define class, so protocol can see MyClass
@protocol MyClassDelegate   //define delegate protocol
    - (void) myClassDelegateMethod: (MyClass *) sender;  //define delegate method to be implemented within another class
@end //end protocol

@interface MyClass : NSObject {
}
@property (nonatomic, weak) id  delegate; //define MyClassDelegate as delegate

@end

MyClass.m file should look like this


#import "MyClass.h"
@implementation MyClass 
@synthesize delegate; //synthesise  MyClassDelegate delegate

- (void) myMethodToDoStuff {
    [self.delegate myClassDelegateMethod:self]; //this will call the method implemented in your other class    
}

@end

To use your delegate in another class (UIViewController called MyVC in this case) MyVC.h:


#import "MyClass.h"
@interface MyVC:UIViewController  { //make it a delegate for MyClassDelegate
}

MyVC.m:


myClass.delegate = self;          //set its delegate to self somewhere

Implement delegate method


- (void) myClassDelegateMethod: (MyClass *) sender {
    NSLog(@"Delegates are great!");
}

having issues?

We have a Questions and Answer section where you can ask your iOS Development questions to thousands of iOS Developers.

Ask Question

FREE Download!

Get your FREE Swift 2 Cheat Sheet and quick reference guide PDF download when you sign up to SwiftMonthly


Sharing is caring

If you enjoyed this tutorial, please help us and others by sharing using one of the social media buttons below.


iOS-Blog Admin Team

Written by:

We're here to help.

Comments

comments