What is a Protocol?

Understand what an Objective-C protocol is, how required and optional methods work, how classes adopt one or more protocols, and how the delegate pattern uses protocols to decouple objects.

A protocol in Objective-C is a list of methods that any class can promise to implement, without that list belonging to any particular class hierarchy. Where inheritance says "you are a kind of this class," a protocol says "you can do these things" — and that shift, from is-a to can-do, is the foundation of nearly every flexible, decoupled design in Objective-C and the Cocoa/Cocoa Touch frameworks built on top of it.

Protocols as a contract, not a class

A protocol declares a set of method signatures with no implementation attached — it is pure interface, the same idea Java and C# call an "interface" and Swift calls a "protocol" (Objective-C's protocol is in fact the direct ancestor of Swift's). Declaring a protocol does not create any storage, does not define any behavior, and cannot be instantiated on its own. It is a promise: "any object that adopts me will respond to these selectors."

This matters because Objective-C, like most Objective-C-family languages, only supports single inheritance — a class can have exactly one superclass. Protocols are the escape hatch. A Car can inherit from Vehicle, but it can also independently adopt Drivable, Insurable, and Sellable — three unrelated capabilities that would be impossible to express through a single inheritance chain. Protocols let you describe capabilities orthogonally to class hierarchy.

Because a protocol carries no implementation, adopting one is a statement of intent that the compiler can check. If a class says it adopts a protocol but fails to implement one of the protocol's required methods, the compiler emits a warning — this is the primary value protocols provide over a class simply happening to implement a method with the right name and signature by coincidence.

Declaring a protocol: required and optional methods

A protocol is declared with @protocol Name and terminated with @end, and inside it method signatures are listed exactly as they would be in an @interface, just without any implementation body. Every method listed before any @optional marker is required by default — any class adopting the protocol must implement it, or the compiler will warn (though, notably, it will still compile; Objective-C protocol conformance is checked, but not strictly enforced the way an abstract method is in some other languages).

The @optional directive switches the methods that follow it to optional — a conforming class may implement them or may not, and callers are expected to check with respondsToSelector: before invoking an optional method, since calling an unimplemented optional method sends a message the object does not understand and crashes at runtime. You can return to @required later in the same protocol to declare more required methods if optional and required methods are interleaved, though in practice most protocols group all required methods first and all optional methods last, exactly as shown below.

Here is the canonical example from the specification — a Printable protocol with one required method and one optional method, and note that it also inherits from the NSObject protocol (distinct from the NSObject class) via <NSObject>, which is a very common convention that lets objects declared as id<Printable> still respond to basic Objective-C runtime methods like respondsToSelector:, isKindOfClass:, and description.

Adopting a protocol

A class adopts a protocol by listing it in angle brackets after its superclass in the @interface declaration: @interface MyClass : NSObject <Printable>. This tells the compiler two things — first, that MyClass promises to implement Printable's required methods (and the compiler will check this against the @implementation block and warn if print is missing), and second, that anywhere in code a MyClass * is expected, an object of that type can also be treated as conforming to Printable.

Adoption is purely additive to the class's own interface. It does not change MyClass's superclass, does not give it any new instance variables, and does not automatically implement anything — the class's @implementation still has to provide real method bodies for every required method it claims to support. Multiple, unrelated classes across a codebase can each adopt Printable independently, and none of them need to share any common ancestor beyond NSObject.

A single class can adopt several protocols at once simply by listing them all, comma-separated, inside the same angle brackets — @interface Document : NSObject <Printable, Serializable, Comparable>. The class must then satisfy the required methods of all three protocols. This is how Objective-C achieves something resembling multiple inheritance of interface (though never of implementation or state) — a class can present as many different capability contracts as it needs to.

Protocol composition

"Protocol composition" refers to building up richer requirements by combining multiple, smaller protocols rather than writing one enormous protocol with every possible method in it. A protocol declaration itself can list other protocols after its name — @protocol RichDocument <Printable, Serializable> — meaning any class adopting RichDocument must also satisfy everything Printable and Serializable require. This lets you build a small vocabulary of focused, single-purpose protocols and assemble them into larger contracts as needed, the same interface-segregation idea found in most statically typed OOP languages.

Composition keeps protocols narrow and reusable. A Printable protocol that only ever talks about printing can be reused by a Document, a Report, and an Invoice class that otherwise have nothing to do with one another, whereas a giant DocumentBehavior protocol bundling printing, saving, emailing, and validating together would force every adopter to implement methods it may not need, or worse, to fake conformance with empty stub implementations.

id<Protocol> — the protocol-typed pointer

The syntax id<Protocol> is one of the most important idioms in Objective-C. Plain id means "a pointer to some Objective-C object, of unknown class" — you can send it any message and the compiler will not check it at compile time, only the runtime will complain if the object cannot respond. id<Printable>, by contrast, still means "an object of unknown, unspecified class," but adds a compile-time promise: whatever class this actually turns out to be, it conforms to Printable and therefore can safely be sent print (and, after a respondsToSelector: check, preview).

This gives you the best of both worlds: you do not need to know or care whether the object is a Document, a Report, or an Invoice — you only care that it can be printed — while still getting compiler warnings if you try to call a method the protocol never promised. A method signature like - (void)renderPrintPreview:(id<Printable>)item; documents, at the type level, exactly what capability the parameter needs, without coupling the method to any specific class.

You will also see NSObject<Printable> * used instead of id<Printable> when a variable should additionally be typed as inheriting from the NSObject class specifically (rather than being any object at all) — but id<Protocol> is by far the more common form, precisely because it maximizes flexibility: any object from any class hierarchy that conforms to the protocol can be assigned to it.

The delegate pattern

The single most common real-world use of protocols throughout Cocoa and Cocoa Touch is the delegate pattern. One object (say, a Downloader) needs to notify some other, unrelated object about events — progress updates, completion, failure — without knowing or caring what class that other object is. The Downloader defines a protocol describing the events it can report, exposes a delegate property typed as id<DownloadDelegate>, and calls methods on that delegate as things happen. Any class — a view controller, a logger, a test harness — can become the delegate simply by adopting the protocol and implementing the methods it cares about.

This inverts control in a clean, decoupled way: the Downloader never imports or references the concrete class of whatever object is listening to it, so the same Downloader can be reused in completely different parts of an app, or in a completely different app, with a different delegate each time. Apple's own frameworks lean on this pattern constantly — UITableViewDelegate, UIScrollViewDelegate, NSURLSessionDelegate, and dozens more all follow exactly this shape: a protocol describing events, a weak delegate property, and optional methods so adopters only implement what they need.

The example below sketches a minimal DownloadDelegate protocol and a Downloader class that calls back through it, mirroring the shape of virtually every delegate-based API you will encounter in real Objective-C code.

Code Examples

This is the protocol from the specification. Printable inherits from the NSObject protocol (giving conformers access to basic runtime introspection methods), declares print as required, and declares preview as optional via the @optional directive — any class adopting Printable must implement print, but implementing preview is up to the adopter. Note the distinction between the NSObject protocol used here in <NSObject> and the NSObject class most Objective-C classes inherit from — they share a name but are different declarations, and conforming to the protocol does not by itself make an object a subclass of the class.

@optional switches every method declared after it to optional, until either @required or @end is reached.

Report adopts two protocols at once, Printable and Serializable, by listing both inside the angle brackets after its superclass. It must implement print and serialize (both required), and it optionally implements preview as well. The variable item is declared as id<Printable> — it does not know or care that the underlying object is actually a Report — yet it can safely call print, and it guards the optional preview call with respondsToSelector: before sending it. Expected result: Printing report: Q3 Summary Preview of: Q3 Summary id<Printable> item = [[Report alloc] init]; assigns a concrete Report instance to a protocol-typed variable that only exposes the Printable contract.

Common mistake: Calling [item preview] directly without the respondsToSelector: check would crash at runtime for any Printable conformer that chose not to implement the optional preview method.

Downloader knows nothing about ViewController — it only knows it has some delegate conforming to DownloadDelegate. ViewController adopts DownloadDelegate and implements the required downloadDidFinish: method, so it can be assigned as the Downloader's delegate and be notified when the download completes, without Downloader ever importing or referencing ViewController's class. This is the same fundamental pattern behind UITableViewDelegate, NSURLSessionDelegate, and most other *Delegate protocols throughout Apple's frameworks.

@property (nonatomic, weak) id<DownloadDelegate> delegate; is the standard shape of a delegate property — weak to avoid a retain cycle, and typed by protocol rather than by any concrete class.

@protocol Printable <NSObject>

- (void)print;

@optional
- (void)preview;

@end
@protocol Serializable <NSObject>
- (NSData *)serialize;
@end

@interface Report : NSObject <Printable, Serializable>
@property (nonatomic, copy) NSString *title;
@end

@implementation Report

- (void)print {
    NSLog(@"Printing report: %@", self.title);
}

- (void)preview {
    NSLog(@"Preview of: %@", self.title);
}

- (NSData *)serialize {
    return [self.title dataUsingEncoding:NSUTF8StringEncoding];
}

@end

id<Printable> item = [[Report alloc] init];
[item print];
if ([item respondsToSelector:@selector(preview)]) {
    [item preview];
}
@protocol DownloadDelegate <NSObject>

@required
- (void)downloadDidFinish:(NSString *)fileName;

@optional
- (void)downloadDidUpdateProgress:(float)progress;

@end

@interface Downloader : NSObject
@property (nonatomic, weak) id<DownloadDelegate> delegate;
- (void)startDownload:(NSString *)fileName;
@end

@implementation Downloader

- (void)startDownload:(NSString *)fileName {
    if ([self.delegate respondsToSelector:@selector(downloadDidUpdateProgress:)]) {
        [self.delegate downloadDidUpdateProgress:0.5f];
    }
    // ... download completes ...
    [self.delegate downloadDidFinish:fileName];
}

@end

@interface ViewController : UIViewController <DownloadDelegate>
@end

@implementation ViewController

- (void)downloadDidFinish:(NSString *)fileName {
    NSLog(@"Finished downloading: %@", fileName);
}

@end

Class hierarchy vs protocol conformance

Downloader and ViewController share no class relationship at all — the only thing connecting them is that ViewController conforms to the DownloadDelegate protocol Downloader expects.

NSObject
            |
      +-----+------+
      |            |
  Downloader   ViewController
      |            |
  delegate:    <DownloadDelegate>
  id<DownloadDelegate>  (implements downloadDidFinish:)
      |____________|
         message flow:
   [self.delegate downloadDidFinish:fileName]

Important Rules

A protocol declares method signatures with no implementation — it never allocates storage and cannot be instantiated on its own.

Methods before @optional are required by default; a class that omits a required method still compiles, but the compiler warns.

@optional methods must be guarded with respondsToSelector: before being called, or an unimplemented one crashes at runtime.

id<Protocol> types an object by capability rather than by class, letting unrelated classes be treated interchangeably wherever only that capability matters.

A class can adopt multiple protocols at once by listing them comma-separated in the angle brackets after its superclass.

The delegate pattern is protocols applied to cross-object notification: one object holds a weak, protocol-typed delegate property and calls back through it.

Where this shows up

Nearly every UIKit and AppKit class that needs to report events back to your code does so through a protocol-based delegate: UITableViewDataSource and UITableViewDelegate drive every table view in iOS, UITextFieldDelegate reports keyboard and editing events, and NSURLSessionDelegate reports networking progress and completion. Understanding protocols is a prerequisite for understanding essentially any Objective-C framework code.

Calling an @optional protocol method without checking respondsToSelector: first.

Always guard an optional call: if ([self.delegate respondsToSelector:@selector(downloadDidUpdateProgress:)]) { [self.delegate downloadDidUpdateProgress:0.5f]; }

Optional methods are, by definition, not guaranteed to be implemented. Sending a message the receiver does not implement raises 'unrecognized selector sent to instance' and crashes the app.

Assuming adopting a protocol in @interface automatically provides implementations for its methods.

Every required method listed in the protocol must still be implemented by hand in the class's @implementation block.

A protocol is pure declaration — listing <Printable> in the interface is a promise to implement print, not an implementation of it. The compiler will warn, but the code still compiles and crashes at runtime if the method is later called.

Declaring a delegate property as strong: @property (nonatomic, strong) id<DownloadDelegate> delegate;

Delegate properties are conventionally weak: @property (nonatomic, weak) id<DownloadDelegate> delegate;

If the delegate holds a strong reference back to the object it is the delegate of (a very common shape, e.g. a view controller owning a Downloader and also being its delegate), a strong delegate property creates a retain cycle and neither object is ever deallocated.

Confusing the NSObject protocol in <NSObject> with the NSObject class most classes inherit from.

Understand that <NSObject> in a protocol declaration means 'also conform to the NSObject protocol,' a separate declaration from the NSObject class, even though they share a name.

An object can conform to the NSObject protocol (and thus respond to things like respondsToSelector: and description) without necessarily inheriting from the NSObject class, though in practice almost every Objective-C object does both.

What does a method listed in a protocol before any @optional directive represent? A. An optional method that may or may not be implemented B. A required method that a conforming class must implement C. A method that is automatically implemented by NSObject D. A private method that cannot be called from outside the class

B. A required method that a conforming class must implement — Every method declared before @optional (or after a later @required) is required by default — the compiler warns if an adopting class fails to implement it.

What must you do before calling an @optional protocol method on an object typed id<Protocol>? A. Nothing — optional methods are always safe to call B. Cast the object to its concrete class first C. Check respondsToSelector: to confirm the object implements it D. Mark the call with @optional in the calling code

C. Check respondsToSelector: to confirm the object implements it — Because optional methods are not guaranteed to be implemented, calling one without first checking respondsToSelector: risks an 'unrecognized selector' crash at runtime.

What does the type id<Printable> mean for a variable? A. The variable must be an instance of a class literally named Printable B. The variable holds an object of unknown class that is guaranteed to conform to the Printable protocol C. The variable can only ever hold nil D. The variable is a C function pointer to the print method

B. The variable holds an object of unknown class that is guaranteed to conform to the Printable protocol — id<Protocol> keeps the flexibility of id (any class) while adding a compile-time guarantee that the object conforms to the named protocol, so its methods can be called safely.

How does a class adopt more than one protocol at once? A. It cannot — a class may adopt only one protocol B. By declaring a separate @implementation block for each protocol C. By listing all the protocols, comma-separated, inside the angle brackets after its superclass D. By subclassing each protocol in turn

C. By listing all the protocols, comma-separated, inside the angle brackets after its superclass — Multiple protocol adoption is written as @interface MyClass : NSObject <ProtocolA, ProtocolB, ProtocolC> — the class must then satisfy the required methods of all three.

In the delegate pattern, why is the delegate property typically declared weak and typed as id<SomeDelegate> rather than as a concrete class? A. Because weak properties are required by the Objective-C compiler for all protocol types B. To avoid a retain cycle and to keep the object decoupled from any specific class that might act as its delegate C. Because strong properties cannot hold objects that conform to protocols D. Because id<SomeDelegate> is faster to access at runtime than a concrete class pointer

B. To avoid a retain cycle and to keep the object decoupled from any specific class that might act as its delegate — weak avoids the retain cycle that commonly forms when the delegate also owns the delegating object, and typing by protocol keeps the delegating object from needing to know anything about the delegate's concrete class.

Define a protocol named Shareable with one required method, shareContent, and one optional method, previewShareSheet. Then write a class Article that adopts Shareable, implements both methods, and demonstrate assigning an Article instance to an id<Shareable> variable and safely calling both methods.

@protocol Shareable <NSObject> - (void)shareContent; @optional - (void)previewShareSheet; @end @interface Article : NSObject <Shareable> @end @implementation Article - (void)shareContent { NSLog(@"Sharing article..."); } - (void)previewShareSheet { NSLog(@"Previewing share sheet..."); } @end id<Shareable> item = [[Article alloc] init]; [item shareContent]; if ([item respondsToSelector:@selector(previewShareSheet)]) { [item previewShareSheet]; }

Remember to check respondsToSelector: before calling the optional method, even though in this exercise you know Article implements it.