Let's say I'm writing a document framework, something I'll be using in many apps, each with different needs. Some apps will need editing, most apps will need importing from documents, some will need writing to documents, most will need onscreen rendering, some will need conversion to export formats.
Naively, I could just add all that needed functionality into each of my class's source files. But the Objective-C category allows me to segregate my code by functional topic.
@interface DocumentNode : NSObject @property(strong, nonatomic, readonly) NSString* type; @property(strong, nonatomic, readonly) NSDictionary* attributes; @property(strong, nonatomic, readonly) NSArray* children; @property(strong, nonatomic, retain) NSObject* cache; @property(strong, nonatomic, readonly) NSString* name; // an attribute -(id) initWithAttributes:(NSDictionary*)startAttributes children:(NSArray*)startChildren type:(NSString*)startType name:(NSString*)aName; @end
and then if I need to have a method to edit the node because I'm writing an editor and not just a viewer, I can create a separate file with an 'Editing' category:
@interface DocumentNode(Editing) -(DocumentNode*) cloneWithAttributes:(NSDictionary*)newAttributes; -(DocumentNode*) cloneWithNewChildren:(NSArray*)newChildren; @end
or if I need a place for my rendering code
@interface DocumentNode(Rendering) -(BOOL) renderIntoContext:(CGContextRef)quartzContext withDocumentVisitContext:(DocumentVisitContext*)visitContext; @end
Now, categories are limited in that you cannot add new member variables to your classes via categories like you could by subclassing your objects. You could use objc_setAssociatedObject to implement the storage for a property, but that would probably be too over the top for just keeping implementation separate. When faced with this design problem, I punted and put the property in the main implementation file, as in the following case where my undo ad redo stacks are unused unless the document needs editing functionality.
@interface GHDocument : NSObject @property(nonatomic, strong) NSMutableArray* undoStack; // only used if Editing is included @property(nonatomic, strong) NSMutableArray* redoStack;In practice, once the code is factored in this way, it can be reused modularly. If I have a project that just acts as a viewer, I just don't include the 'DocumentNode+Editing.h' in my other source files, and I don't compile the 'DocumentNode+Editing.m' file by unchecking it's inclusion in Xcode. For small projects this might not matter much, but when you are building up a large codebase or want to reuse just a small bit in another project, you'll regret not factoring things for modularity from the very beginning.