Tuesday, March 6, 2012

A (Very) Gentle Introduction to Protocols in Objective-C

Protocols are a powerful abstraction in Objective-C OOP. This is a gentle introduction and should be treated as such. For comprehensive cover of Protocols, the Apple Developer Guide is the de facto resource.  I'm going to focus on formal protocols here and show an example of how they can be used to allow a View to call a method on its ViewController without breaking good design principles.

I come from a C# background so I think of them rather like Interfaces but with some differences. The similarities are that they both offer a contract that allow objects to make use of other objects behavior without the need for subclassing. Developers tend to favor Composition over inheritance as it can provide a more flexible way of building a system. It is a good design principle and worth understanding the benefits of to truly appreciate Protocols or Interfaces.

Protocols have some interesting features and although some of the ideas are the same as Interfaces, the terminology can take a bit of getting used to.
  • The object that declares the prototype will be the object that calls methods on it. 
  • Another object may "adopt" the prototype, meaning it implements the methods outlined in the prototype. 
Protocols are essentially lists of methods. Some methods are required to be implemented and some can be marked as optional. If the "adopter" of an interface (i.e. the object that implements it and provides the behavior) does not implement all required methods you will get a compiler warning.

@protocol MyProtocol
- (void)requiredMethod;
- (void)anOptionalMethod;
- (void)anotherOptionalMethod;
- (void)anotherRequiredMethod;
An basic example where I have started to use Protocols is when a View needs to call a method on its ViewController. A View should not "have" a ViewController directly. Sometimes a View does need to call a Controller to receive more data or updated data. You can do this through a Protocol.
  • I declare Protocol in my View.h 
  • I call the protocol method I need in my View.m 
  • I implement the Protocol in my ViewController. 
  • I set the ViewController to be the delegate for that protocol.
// Here a declaration of a View includes the declaration of a Protocol. 
// This means the view will want to call methods declared in this protocol
// and another object will have adopted the protocol and implemented the methods to provide behavior.
@class GraphView;

@protocol GraphViewDelegate
- (double)evaluateExpressionForX:(double)x;

@interface GraphView : UIView { 
    id  delegate;
// The declaring object actually goes ahead and calls the method it needs
// Note: the declaring object has no idea who implements the protocol or how they implement it. Nice.
double y = [self.delegate evaluateExpressionForX:someValue];
// Declare that you adopt the protocol in your interface declaration.
@interface GraphViewController : UIViewController 

- (void)viewDidLoad {
    // State that you will take care of messages from graphView (provided you have the protocol implementation!)
    self.graphView.delegate = self;

- (double)evaluateExpressionForX:(double)x {
    // do some calculations
    return result;
That's it. Now the View can message the delegate and get a response back. The View has no idea who implemented the protocol or how they went about implementing it. The Controller is in charge of declaring that it will look after the messages from the View through the Protocol. This is one short quick example of the power of Protocols.

1 comment: