Typedef Objective-C Polymorphism

21 Mar 2015

</br>

Polymorphism in Objective-C can be achieved with protocols. Protocols can be used to create abstract interfaces and hide classes. The traditional approach to implementing multiple protocols can result in hard to maintain code.

For example, here’s 2 subclasses of UIView that share similar capabilities:

@protocol Printable <NSObject>

- (void)printToFile:(NSFileHandle *)file;

@end

@interface ViewA : UIView <Printable>

@end

@interface ViewB : UIView <Printable>

@end


It’s straight forward to vend an abstract interface that could be backed by either of these subclasses:

@interface Controller : NSObject

// This view could be type ViewA, ViewB, or any other
// view that implements the Printable protocol.
// The actual class is an implementation detail.
@property (nonatomic) UIView <Printable> *view;

@end


It’s straight forward to consume it as well:

Controller *controller;
UIView <Printable> *view = controller.view;
....


This pattern breaks down if capabilities need to be added to the type. For example, if the view needed to expose the additional @protocol Logable.

The interface declaration must be changed:

@interface Controller : NSObject

@property (nonatomic) UIView <Printable, Logable> *view;

@end


There’s downsides to this change: all existing uses need to change, it’s not nice to read, and it’s hard to type. It’s unmaintainable.

In example:

Controller *controller;
UIView <Printable, Logable> *view = controller.view;
....


Potential alternatives might be to make Printable descend from Logable or even just add all the methods from Logable. If you’re the vendor of Printable, the change is certainly possible. But, existing implementors of Printable, might not need to be extended with Logable. This is asking for strange semantics and a bloated protocol.

There’s an oldschool technique that can be used to simplify the interface. It’s called typdeffing and its widely used in Objective-C apps, just not for this purpose.

I call it Typedef’d polymorphism:

typedef UIView <Printable, Logable> View;
“Typdef View as a UIView that implements Printable and Logable.”

By declaring the new type, we introduce a clean layer of abstraction. The new type, View, is a UIView and implements both protocols.

It’s easier for humans to parse than UIView <Printable, Logable> *. It reduces the complexity to a single place. It’s maintainable.

It radically simplifies the interface:

@interface Controller : NSObject

@property (nonatomic) View *view;

@end


Controller *controller;
View *view = controller.view;
....


The newly found type abstraction layer adds opportunity for (sinful) flexibility. For example:

The type can be directly implemented:

// Valid Objective-C
@interface PrintableLogableView : View

@end


The type can be conditionally defined:

// Valid Objective-C
#ifdef DEBUG
    typedef UIView <Printable, Logable, DebugCapabilites> View;
#else
    typedef UIView <Printable, Logable> View;
#endif


The possibilities are endless!


I’ve never see this approach used in Apple frameworks i.e. this type of problem isn’t exposed in UIKit. I don’t think this approach is widely used at all.

Typdeffing is not only useful to define simple types: it’s a powerful technique that can be used to create flexible, maintainable, abstract interfaces. With great power comes great responsibility.

For more fun Objective-C trickery, check out Mike Ash’s recent Friday Q&A on Preprocessor Abuse and Optional Parentheses.

Published on 21 Mar 2015 Find me on Twitter!