Categories

Categories are a way to change the behavior of a class - even if you don't have access to the source code. It's important to note that the inclusion of a category impacts all instances of a class and all subclasses.

A category has direct access to all private private in the original class. Ironically, a category cannot add new properties - only methods. Also, since multiple categories can be created for a single class, it's possible for some of the new methods to clash. When this occurs, the behavior is undefined. (I'll admit that I'm a bit skeptical about categories - they seem to add a lot of uncertainty without enough control.)

Despite these reservations, I'll add a category to the gas can class. This category, named Safety, provides methods that ensure the can is either fully open or fully closed. It's also important to note that I'll use the MarineGasCan class to demonstrate the behavior. (Since MarineGasCan is a subclass of GasCan, it also gets all of the category-based methods that are defined in Safety.

The GasCan interface:

  1. #import <Foundation/Foundation.h>
  2.  
  3. @interface GasCan : NSObject {
  4. @private
  5. int size;
  6. @protected
  7. BOOL spoutOpen;
  8. BOOL valveOpen;
  9. }
  10.  
  11. @property (nonatomic) float level;
  12.  
  13. -(id) initWithSize: (int)x;
  14. -(id) init;
  15. -(void) pourContents;
  16. -(int) size;
  17. -(void)openSpout: (BOOL)x andValve: (BOOL)y;
  18. @end

The new category interface named Safety. (The file name is GasCan+Safety.h)

  1. #import "GasCan.h"
  2.  
  3. @interface GasCan (Safety)
  4. -(void)open;
  5. -(void)close;
  6. @end

The implementation of the category (The file name is GasCan+Safety.m)

  1. #import "GasCan+Safety.h"
  2.  
  3. @implementation GasCan (Safety)
  4. -(void)open {
  5. spoutOpen = YES;
  6. valveOpen = YES;
  7. }
  8.  
  9. -(void)close {
  10. spoutOpen = YES;
  11. valveOpen = YES;
  12. }
  13.  
  14. @end

The main.m file:

  1. #import "GasCan.h"
  2. #import "GasCan+Safety.h"
  3. #import "MarineGasCan.h"
  4.  
  5. int main(int argc, char * argv[]) {
  6. @autoreleasepool {
  7. MarineGasCan *gCan = [[MarineGasCan alloc] init];
  8. [gCan setLevel:3];
  9. [gCan openSpout:NO andValve:NO];
  10. [gCan pourContents];
  11. [gCan open];
  12. [gCan pourContents];
  13.  
  14.  
  15. NSString *message = @"The level in your gas can is: ";
  16. NSLog(@"%@ %f",message, gCan.level);
  17. }
  18. }