Protocols and Delegation

This section documents modern Objective-C as implemented by Apple Clang in the current Xcode release — Objective-C 2.0 plus ARC, literals and subscripting, instancetype, Clang modules, lightweight generics, nullability and @available — as published at Apple Developer Documentation and the Clang Objective-C specifications, which are the references these pages are written and verified against.

This content was generated with the assistance of AI and should be verified against developer.apple.com before being relied on in production.

This section’s bibliography lists the reference material consulted while preparing these pages.

A protocol is a named list of method declarations with no implementation — Objective-C’s interface type. Any class may adopt any number of protocols, which is how the language provides the "implement several contracts" capability that single inheritance alone cannot. Protocols underpin delegation, the pattern Cocoa uses almost everywhere in place of subclassing.

Declaring a Protocol

// MyDownloaderDelegate.h
@class MyDownloader;

@protocol MyDownloaderDelegate <NSObject>

@required
- (void)downloader:(MyDownloader *)downloader didFinishWithData:(NSData *)data;

@optional
- (void)downloader:(MyDownloader *)downloader didUpdateProgress:(double)progress;
- (void)downloaderDidCancel:(MyDownloader *)downloader;

@end

@required methods must be implemented by any adopter — the compiler warns if one is missing. @optional methods may be absent, so the sender must check before calling. Without either directive, declarations are @required.

The Cocoa naming convention for delegate methods is worth following exactly: the first argument is the sender, and the selector reads as a sentence about what happened (didFinish…, willBegin…, should…). It makes delegate code self-documenting at the call site.

Adopting and Conforming

A class adopts protocols by listing them in angle brackets:

@interface ViewController : UIViewController <MyDownloaderDelegate, NSCoding>
@end

Adopt privately — in the class extension — whenever conformance is an implementation detail rather than part of the class’s public contract:

// ViewController.m
@interface ViewController () <MyDownloaderDelegate>
@end

id<Protocol> Typing

The most useful thing about a protocol is as a type: "any object at all, provided it can do these things".

@property (nonatomic, weak) id<MyDownloaderDelegate> delegate;

- (void)setHandler:(id<MyDownloaderDelegate>)handler;

// A concrete class plus a protocol, when you need both:
@property (nonatomic, strong) UIView<MyHighlightable> *highlightedView;

id<MyDownloaderDelegate> is checked at compile time: sending a message not in the protocol (and not in NSObject) is a warning. That makes it strictly better than a bare id for this purpose. And it is better than a concrete class type, because it lets any class — including a test double — satisfy the requirement.

A protocol object itself is obtained with @protocol(…​):

Protocol *p = @protocol(MyDownloaderDelegate);
NSString *name = NSStringFromProtocol(p);        // @"MyDownloaderDelegate"

Protocol Inheritance and the NSObject Protocol

A protocol may extend others, inheriting all their requirements:

@protocol MyReadable <NSObject>
- (NSData *)readData;
@end

@protocol MyReadWritable <MyReadable>        // requires readData too
- (void)writeData:(NSData *)data;
@end

Almost every protocol should inherit from NSObject — note this is the NSObject protocol, not the class. Foundation declares both with the same name; <NSObject> in a protocol list means the protocol. It declares the fundamental messages (isEqual:, hash, description, respondsToSelector:, retain, release), and without it the compiler will not let you send even respondsToSelector: to your id<MyProtocol> — which is precisely what the optional-method idiom requires.

@protocol Bad                      // does not inherit <NSObject>
- (void)doSomething;
@end

id<Bad> obj = …;
// [obj respondsToSelector:@selector(doSomething)];   // warning: not in the protocol

Run-Time Conformance Checks

// Does this object claim the whole protocol?
if ([object conformsToProtocol:@protocol(MyDownloaderDelegate)]) { … }

// Does it implement this particular (optional) method?
if ([object respondsToSelector:@selector(downloader:didUpdateProgress:)]) { … }

// Class-level query:
if ([SomeClass conformsToProtocol:@protocol(NSCopying)]) { … }

The distinction matters: conformsToProtocol: answers "was this protocol declared in the adoption list", which says nothing about whether the @optional methods were actually implemented. For calling an optional method, respondsToSelector: is the only correct check.

Prefer either of these to isKindOfClass: when what you need is a capability — it is more flexible, survives refactoring, and works with proxies and class clusters.

The Delegate Pattern

Delegation lets one object hand off decisions or notifications to another, without either knowing the other’s class. It is the single most common design pattern in Cocoa.

// MyDownloader.h
@interface MyDownloader : NSObject
@property (nonatomic, weak) id<MyDownloaderDelegate> delegate;   // weak! see below
- (void)start;
@end
// MyDownloader.m
@implementation MyDownloader

- (void)finishWithData:(NSData *)data {
    // A @required method: the delegate may be nil, but a message to nil is a no-op,
    // so no guard is needed.
    [self.delegate downloader:self didFinishWithData:data];
}

- (void)reportProgress:(double)progress {
    // An @optional method: respondsToSelector: is mandatory here.
    if ([self.delegate respondsToSelector:@selector(downloader:didUpdateProgress:)]) {
        [self.delegate downloader:self didUpdateProgress:progress];
    }
}

@end

And on the other side:

// ViewController.m
@interface ViewController () <MyDownloaderDelegate>
@property (nonatomic, strong) MyDownloader *downloader;      // strong: the controller owns it
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.downloader = [[MyDownloader alloc] init];
    self.downloader.delegate = self;             // the back-reference is weak
    [self.downloader start];
}

- (void)downloader:(MyDownloader *)downloader didFinishWithData:(NSData *)data {
    [self renderData:data];
}

@end

The Callback Sequence

sequenceDiagram participant VC as ViewController
(the delegate) participant D as MyDownloader participant N as Network VC->>D: alloc/init VC->>D: downloader.delegate = self
(weak reference back to VC) VC->>D: start D->>N: begin request N-->>D: bytes arrive D->>D: respondsToSelector:
@selector(downloader:didUpdateProgress:) alt delegate implements the optional method D-->>VC: downloader:didUpdateProgress: VC->>VC: update the progress bar else not implemented D->>D: skip the call end N-->>D: transfer complete D-->>VC: downloader:didFinishWithData:
(@required -- called unconditionally) VC->>VC: render the data Note over VC,D: VC holds D strongly, D holds VC weakly.
If both were strong, neither would ever be deallocated.

Why Delegates Are weak

The owner holds the worker strongly; the worker must therefore hold the owner weakly. If both references were strong, the pair would form a retain cycle and neither object would ever be deallocated — a leak that ARC cannot detect or break.

@property (nonatomic, weak) id<MyDownloaderDelegate> delegate;     // correct
// @property (nonatomic, strong) id<MyDownloaderDelegate> delegate; // leaks

weak brings a second benefit: the reference is zeroed automatically when the delegate is deallocated, so a late callback goes to nil and is harmlessly ignored rather than crashing on a dangling pointer.

Two caveats:

  • A few classes need assign/unsafe_unretained instead — some older Core Foundation-backed classes do not support weak references. These do dangle, so such a delegate must be cleared in dealloc.

  • A block-based callback is not automatically safe. A copy block property retains everything it captures, so capturing self inside a completion handler creates exactly the cycle weak avoids here. See Blocks.

Retain cycles in general are covered in Automatic Reference Counting.

Delegate versus Data Source

Cocoa splits the pattern in two whenever both roles apply — UITableView has a delegate and a dataSource:

Data source Delegate

Question answered

"What should I display?"

"Something happened — what now?"

Direction

Object pulls data from you

Object pushes events to you

Typical methods

numberOfRowsInSection:, cellForRowAtIndexPath:

didSelectRowAtIndexPath:, willDisplayCell:

Usually @required

Yes

No

Keeping them separate lets one object supply the content while another handles the interaction.

When Not to Delegate

Delegation is right for a one-to-one, ongoing relationship. Other shapes have better tools:

Need Use

One-to-one, several related callbacks over time

Delegate protocol

A single "when you’re done" callback

A completion block — keeps the caller’s code in one place

One-to-many broadcast

NSNotificationCenter, or KVO for property changes

Loose coupling to a UI control

Target-action

See Also