One of Objective C’s nicer features is the “Category”. A Category is simply a way to add your own methods to existing classes. And the best part of it: You don’t even need to have the source code to that class.
If you have some code for adding all those backslashes to a string so you can pass it to a command-line tool, then you can just put it into an NSString-category and immediately every NSString in your program understands this new method.
There’s just one problem with this: It’s very easy to mis-use. Since Object-oriented programming was invented, people seem to be oddly reluctant to create a new class. Also, many people have problems deciding when an object should e.g. be a dictionary and when it should only have a dictionary.
Whenever you extend a class (be it one of your own classes or an extension to another class using a category), or subclass, it helps to keep in mind that you want to keep your code easy to maintain. You want to reuse code so that you have to fix each bug only once in a central place and it’s fixed for good, and you want to take advantage of the fact that the less code you write, the less bugs can be in it.
So, to keep your code comprehensible at first read, your first question when extending a class should be: Does what I do still fit the name of the class? E.g. if you’re subclassing NSDictionary, what you end up with should in some way still be a dictionary. If you subclass NSDictionary and you end up with a data source, you should ask yourself whether what you’re doing is really such a good idea.
The second question you should be asking yourself is whether you’re crossing any boundaries. E.g. in above example of a dictionary (part of the “model” layer in the Model-View-Controller pattern) that gets subclassed and becomes a data source (which, strictly spoken, is part of the controller layer, though it’s mainly a “model-controller”), you’re watering down the MVC boundaries that are so useful in synchronizing multiple views with your data or keeping your application portable. It would probably be much better to create a new “DictionaryController” class that can connect to a dictionary. Of course you can give it the optional feature of creating the dictionary if needed (it would have a dictionary, not be one).
The third question should be: Is this really reusable? If you subclass NSMutableDictionary as a data source, what happens if you suddenly have an NSDictionary? The code to view an NSMutableDictionary or an NSDictionary is exactly the same, but your subclass would have to be reimplemented for both of them. No good idea. Better create a controller that can then be given either type of dictionary. Sure, you could use a category on NSDictionary, and NSMutableDictionary would probably inherit that, but there’s still point four below…
An extension of this reuse consideration is the thought of rewriting: If you write a category and immediately realize that for one very common use you’ll probably end up needing you’d have to rewrite it, maybe even as a separate object, then it probably isn’t reusable enough. Categories and objects aren’t very different in effort and lines of code. A category is usually self-contained and reusable, so it should probably have its own file, just like a class. So, if something might work better as a class, just make it one, it doesn’t hurt. And in addition, a separate object can be easily instantiated in a NIB and connected to another object. With a category and an existing object, that’s not so easy.
Categories are also where question four comes in: If you’re creating a category, do you really want to carry those methods around with every object? This is not a peformance consideration, but rather one of complexity and unwanted side effects. After all, it’s perfectly all right to write a classic C function that converts an object to another type if you only need that in two places, and it’s just as reusable to have a separate controller object that does repeated conversion and translation between data types (like NSFormatter). The ground rule is, if you can’t honestly say to yourself that you will use a particular method in a category on another class a dozen times, you probably shouldn’t be adding it.
As you see, there’s no hard and fast rule when to use a category and when not to (well, at least I haven’t managed to formulate it yet). But hopefully my rambling above will give you a checklist to go through mentally when you’re trying to decide whether a category, subclass, or a new class would be better in a particular situation.
If you have any suggestions, or have insights of your own to share, feel free to leave a comment.