Cocoa allows developers to declare a category that adds methods to an exisiting class. The category pattern lets you extend existing classes, even if you don’t have access to the source code, implement different methods of the same class in different frameworks, and organize the implementation of a new class, even spreading it across different files.
The most significant limitation is that it can’t add instance variables to the class. The authors point out that there’s a way around this, using the Associative Storage pattern, covered in Chapter 19. On the other hand, if you need new instance variables, it’s probably time to think about subclassing.
Hillegass’s book has a chapter on categories (22 in the 3rd edition, 19 in the 2nd), so you’ve probably seen categories. Hillegass uses it to add a new method to NSString, while Buck & Yacktman create a new class, MYDie, and then use a category to add a new method to it.
MYDie uses a bad method of generating random die rolls, and the category replaces the bad method with a better one. It’s an example of how you could use a category to change the behavior of a class you don’t have access to.
The book doesn’t provide a sample program for this chapter, but the code in the text is short and simple enough to type in yourself, and it’s easy to create a main program that makes use of MYDie. Mine used a loop to roll two dice, and then check to see if they came up boxcars. You may want to add NSLog statements in the original and modified versions of the roll method, to verify which version is actually being called.
I had a lot of trouble getting my example to work, before finally figuring out that the problems were both related to capitalization. In the file setting up the category for the class MYDie, I mis-typed the name as MyDie. The compiler gave me the error Cannot find interface declaration for 'MyDie', and I just couldn’t see the problem for the longest time.
The other problem was the warning 'MYDie' may not respond to '-isBoxCar', when the method I wanted was isBoxcar. I should have spotted this one earlier, since isBoxcar showed up in light blue (used for class names and method names), while isBoxCar showed up in black.
The remaining problem was that I had declared d1 and d2 as instances of the MYDie class, but hadn’t allocated and initialized them. That also had the effect of hiding the problem with the method name: since the messages were being sent to nil, they didn’t do anything. Going back and re-compiling to get the error messages for this write-up, I found that using proper allocation and initialization with the bad method name made the program crash.
Leave a comment if you’s like me to post my main program. I’m not comfortable posting Buck & Yacktman’s code, not wanting to get into copyright issues.