How to Customize the Behavior of iOS Framework Classes: Subclassing and Delegating
Although you’ll be creating classes of your own (especially model classes) for your iOS app, often you’re going to want to customize the behavior of a particular framework class. You have three ways to go about it:
Objective-C, like other object-oriented programming languages, permits you to base a new class on a class that’s already declared. The base class is called a superclass; the new class is its subclass. Each subclass that you define inherits methods and instance variables of its superclass.
Some framework classes are expected to be subclassed. Among them are view controllers, which you’ll be subclassing quite a bit. In fact, there are some classes that are never instantiated directly: These are called abstract classes. Their subclasses can be instantiated directly: These are called concrete instances.
Almost all object-oriented programming languages support subclassing. However, there’s a bit of a problem sometimes. It’s called the multiple inheritance problem: it’s when you want a class to be a subclass of two classes. There’s no problem if both subclasses are in the class hierarchy. You could have a class called structure, a subclass called residential structure, and a subclass of both called house.
But what do you do if you want house to be a subclass both of structure and of investment?
The Delegation pattern
Delegation is a pattern used extensively in the iOS frameworks, so much so that, if you want to do any serious app development work, you’re going to have to get your head around it. In fact, when you do understand it, your life will instantly become much easier to manage.
Instead of subclassing an object, one object delegates the task of implementing one of its responsibilities to another object. You’re using a behavior-rich object supplied by the framework as is and putting the code for program-specific behavior in a separate (delegate) object. When a request is made of the framework object, the method of the delegate that implements the program-specific behavior is automatically called.
iOS frameworks rely heavily on the delegation pattern.
For example, the UIApplication object handles most of the actual work needed to run the app. But, as you saw, it sends your application delegate the application:didFinishLaunchingWithOptions: message to give you an opportunity to create model objects that are unique to your app.
When a framework object has been designed to use delegates to implement certain behaviors, the behaviors it requires (or gives you the option to implement) are defined in a protocol.
Protocols define an interface that the delegate object implements. In iOS, protocols can be formal or informal. Formal protocols include support for things like type checking and runtime checking to see whether an object conforms to the protocol.
In a formal protocol, you usually don’t have to implement all the methods; many are declared optional, meaning that you have to implement only the ones relevant to your app. Before a formal protocol attempts to send a message to its delegate, the host object determines whether the delegate implements the method (via a respondsToSelector: message) to avoid the embarrassment of branching into nowhere if the method isn’t implemented.
A protocol can be adopted by any class as long as it implements the required methods of the protocol. Thus, by adopting one or more protocols and becoming a delegate, a single class can implement functionality from two other classes — it provides an approximation of multiple inheritance.