Of the many other available preprocessor directives, the one you’ll use most often is
#define. It is followed by a name and a value; at preprocess time, the value is substituted for the name down through this code file. As K&R very well explain (K&R 1.4), this is a good way to prevent “magic numbers” from being hidden and hard-coded into your program in a way that makes the program difficult to understand and maintain.
For example, in an iOS app that lays out some text fields vertically, I might want them all to have the same space between them. Let’s say this space is 3.0. I shouldn’t write 3.0 repeatedly throughout my code as I calculate the layout; instead, I write:
#define MIDSPACE 3.0
Now instead of the “magic number” 3.0, my code uses a meaningful name,
MIDSPACE; at preprocessor time, the text
MIDSPACE is replaced with the text
3.0. So it amounts to the same thing, but if I decide to change this value and try a different one, all I have to do change is the
#define line, not every occurrence of the number 3.0.
#define simply performs text substitution, so any expression can be used as the value. Sometimes you’ll want that expression to be an NSString literal. In Cocoa, NSString literals can be used as a key to a dictionary or the name of a notification. (Never mind for now what a dictionary or a notification is.) This situation is an invitation to error. If you have a dictionary containing a key
@"mykey" and you mistype this elsewhere in your code as
@"mikey", the compiler won’t complain, but your program will misbehave. The solution is to define a name for this literal string:
#define MYKEY @"mykey"
MYKEY throughout your code instead of
@"mykey", and if you mistype
MYKEY the preprocess substitution won’t be performed and the compiler will complain, catching the mistake for you.
#define directive can also be used to create a macro (K&R 4.11.2), a more elaborate form of text substitution. You’ll encounter a few Cocoa macros in the course of this book, but they will appear indistinguishable from functions; their secret identity as macros won’t concern you.
#warning Don't forget to fix this bit of code
There is also a
#pragma mark directive that’s useful with Xcode; I talk about it when discussing the Xcode programming environment (Chapter 9).