views:

485

answers:

4

In Objective-C, my understanding is that the directive @"foo" defines a constant NSString. If I use @"foo" in multiple places, the same immutable NSString object is referenced.

Why do I see this code snippet so often (for example in UITableViewCell reuse):

static NSString *CellId = @"CellId";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellId];
if (cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:style reuseIdentifier:CellId];

Instead of just:

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CellId"];
if (cell == nil) {
    cell = [[UITableViewCell alloc] initWithStyle:style reuseIdentifier:@"CellId"];

I assume it is to protect me from making a typo in the identifier name that the compiler wouldn't catch. But If so, couldn't I just:

#define kCellId @"CellId"

and avoid the static NSString * bit? Or am I missing something?

+8  A: 

It's good practice to turn literals into constants because:

  1. It helps avoid typos, like you said
  2. If you want to change the constant, you only have to change it in one place

I prefer using static const NSString* static NSString* const because it's slightly safer than #define. I tend to avoid the preprocessor unless I really need it.

Tom Dalling
And string constants can be easily examined in gdb. #define is a real pain. But your use of const here is incorrect. It needs to be "static NSString* const". Your const ordering doesn't actually achieve anything useful in objc. Try reassigning your string variable done this way versus my way and you'll see that in one case you get a compiler error and the other you don't.
Rob Napier
+2  A: 

It is not guaranteed that when using @"foo"in multiple places the runtime uses the same storage for them, and certainly may not be the case across compilation unit or library boundaries.
I would rather use static NSString *string = @"foo", especially with a lot of literal strings.

kiamlaluno
+2  A: 

You should make the static variable const.

One difference between static variable and a macro is that macros don't play well with debuggers. Macros also aren't type-safe.

Much of the static-var-vs-macro advice for C and C++ applies to Obj-C.

outis
Thanks for the references, I hadn't seen those.
Sickpea
Search SO (via Google) for `"static const" macro` for more.
outis
A: 

I assume it is to protect me from making a typo in the identifier name that the compiler wouldn't catch.

Correct. It's just basic defensive programming practice. The compiled result (hopefully) is the same either way.

But If so, couldn't I just:

#define kCellId @"CellId"

and avoid the static NSString * bit? Or am I missing something?

Yes. But the kCellId symbol would be globally defined, at least in your compilation unit. Declaring a static variable makes the symbol local to that block.

You will typically see string constants defined as global variables or static variables rather than preprocessor defines. This helps ensure that you're only dealing with a single string instance between different compilation units.

Darren