static NSString usage vs. inline NSString constants

Viewed 22570

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?

6 Answers

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.

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.

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.

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.

Related