Categories

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 functionality—and 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.

Example 1-11. Defining a category interface
#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.

Example 1-12. Implementation of a category
#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.

Warning

A category is not a substitute for a subclass. You should not redefine methods already in a class or a class’s superclass—add only new methods to the class.

Protocols

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.

Example 1-13. Defining a protocol
@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.

Example 1-14. Conforming to a protocol in a class interface
#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.

Example 1-15. Checking to see if an object conforms to a protocol
if([song conformsTo:@protocol(Playable)]) {
    [song play];
} else {
    // Issue a warning or do something else reasonable here
}

Get Cocoa in a Nutshell now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.