Inheritance is not the only way to add functionality to a class. With an Objective-C language construct called a category, you can add methods to an existing class, thereby extending its functionalityand the functionality of its subclasses.
A category interface declaration looks like a class interface declaration, with one exception: the category name is listed in parentheses after the class name, and the superclass is not mentioned. For example, if you wanted to add a rot13 method to the NSString class to get the rot13 version of any string, the category interface would be defined as shown in Example 1-11.
#import "NSString.h" @interface NSString (Obfuscation) - (NSString *)rot13; @end
The category's implementation looks like the implementation of a class itself. Example 1-12 shows an interface implementation.
#import "Obfuscation.h" @implementation NSString (Obfuscation) - (NSString *)rot13 { NSString * rot13string; // Perform logic to shift each character by 13 return rot13string; } @end
Remember that a category can't declare new instance variables for a class; it can only add methods to an existing class.
|
Class and category interfaces define the methods that belong to a particular class. However, you might want many different classes, otherwise unrelated to one another, to perform the same set of methods. Objective-C does not support multiple inheritance, but because of the language's dynamic nature, its support for protocols (declaration of a group of methods under a name) fills the need. A protocol defines the methods that a class is expected to implement in order to function appropriately while leaving the implementation of those methods to the class.
Like classes and categories, protocols are defined in interface header (.h) files. To define a set of methods that apply to objects controlled by a media player, define the protocol as shown in Example 1-13.
@protocol Playable - (void)play; - (void)stop; @end
A class adopts a protocol by listing the protocols in the file's interface declaration. Example 1-14 shows the syntax used in the interface declaration to indicate that the Song class conforms to the Playable protocol.
#import <Cocoa/Cocoa.h>
#import "Playable.h"
@interface Song : NSObject <Playable> {
id title;
}
- (id)title;
- (void)setTitle:(id)aTitle;
@end;
A class or category that adopts a protocol must implement all methods defined by that protocol. The compiler issues a warning if this requirement is not satisfied. Additionally, you can check whether or not objects conform to a particular protocol. If a media player wants to make sure that the Song class conforms to the Playable protocol, the check in Example 1-15 could be used.
if([song conformsTo:@protocol(Playable)]) { [song play]; } else { // Issue a warning or do something else reasonable here }