Interface Segregation and Objective C Delegates

The fourth principle of the SOLID principles is the Interface Segregation Principle. According to Wikipedia, the authority on most truth, this principle states that “no client should be forced to depend on methods it does not use”. This principle can help in cleaner and more intuitive designs of protocols and delegates.Most Objective C introductory tutorials introduce developers to the idea of delegates. For example, if you have a table view controller and table view cells, the table view cells can send messages to the table view controller using a delegate.

The definition for the table view cell could look something like this:

@protocol MyTableViewCellDelegate <NSObject> 
    - (void)doSomething; 
@end 

@interface MyTableViewCell : UITableViewCell 
@property (nonatomic, weak) id<MyTableViewCellDelegate> delegate; 
@end

And the definition of the table view controller could look something like this:

@interface MyTableViewController : UITableViewController <MyTableViewCellDelegate> 
@end

In the implementation of the table view controller, when dequeuing the cell and setting it up, the delegate of the cell should be set to the table view controller.

For a simple example like this, this is ok. But as the application gets more complicated, the delegate definition can get more complicated. For example, if the table view cell manages individual audio, video and other text items, the protocol definition of the delegate could end up looking as follows:

@protocol MyTableViewCellDelegate 
- (void)addAudioItem:(AudioItem *)audioItem; 
- (void)showAudioItem:(AudioItem *)audioItem; 
- (void)deleteAudioItem:(AudioItem *)audioItem; 

- (void)addPhotoItem:(PhotoItem *)photoItem; 
- (void)showPhotoItem:(PhotoItem *)photoItem; 
- (void)deletePhotoItem:(PhotoItem *)photoItem; 
@end

This can get confusing with added complexity. In addition to this, the cell may be used in another context that doesn’t have either audio or photo items, forcing the class that implements the protocol (the view controller in this case) to implement methods it doesn’t require.

To simplify this, the protocol can be broken down into smaller protocols, as follows:

@protocol AudioItemHandler 
- (void)addAudioItem:(AudioItem *)audioItem; 
- (void)showAudioItem:(AudioItem *)audioItem; 
- (void)deleteAudioItem:(AudioItem *)audioItem; 
@end 

@protocol PhotoItemHandler 
- (void)addPhotoItem:(PhotoItem *)photoItem; 
- (void)showPhotoItem:(PhotoItem *)photoItem; 
- (void)deletePhotoItem:(PhotoItem *)photoItem; 
@end

The table view cell can then reference both of these items as follows:

@interface MyTableViewCell : UITableViewCell 
@property (nonatomic, weak) id<AudioItemHandler> audioItemHandler; 
@property (nonatomic, weak) id<PhotoItemHandler> photoItemHandler;
@end

And lastly, the class that implemented the delegate protocol now implements both of the smaller protocols:

@interface MyTableViewController : UITableViewController <AudioItemHandler, PhotoItemHandler> 
@end

This way, the protocols can be used separately and aren’t bound to be used together, increasing the flexibility. In addition to this, each responsibility can then be handled by different objects.

Patrick Kayongo

I create and maintain software. Pan-African.

Johannesburg, South Africa