views:

13964

answers:

5

According to Cocoa Programming for Mac OS X, 3rd Edition, on page 202 (chapter 13):

You will be registering, reading, and setting defaults in several classes in your application. To make sure that you always use the same name, you should declare those strings in a single file and then simply #import that file into any file in which you use the names. There are several ways to do this. For example, you could use the C preprocessor’s #define command, but most Cocoa programmers use global variables for this purpose.

Is this really the correct best practice? Global variables? That seems insane to me – counter to everything I’ve ever been taught.

Would a better design be a simple Singleton class with these defined? Or is it really the correct best practice to go global? Is there a better pattern than either, given that many people consider Singletons to be globals in a pretty dress?

+11  A: 

Global variables or a singleton will accomplish the same thing here. Both can be used to turn 'key' names in Cocoa that won't throw a compiler error if it's misspelled into a compiler error. That's the main purpose. Global variables are a bit easier though seeing as it requires less typing.

Instead of doing this:

[myArray setObject:theObject forKey:MyGlobalVariableKeyName];

You'd have to do something along the lines of:

[myArray setObject:theObject 
            forKey:[[MySingletonVariableClass getInstance] myVariableKeyName];

Global variables are essentially less typing for the same effect.

Grant Limberg
+2  A: 

Constant globals that are set at compile time and never change are acceptable to me. If you hard code a string, it's the same thing, just hidden by the compiler. I'll avoid mutable globals like the plague.

Remember, Apple itself uses the same technique. Many of the constants I expected to be defines are actually constants. You'll get link errors if the headers are reachable but the framework is not.

A: 

It depends on the design of your software. Suppose you have a job management software and one of your "defaults" is a list of directories in which various items can be saved.

For each Job you can have a storagefile member that is a singleton that load up the user preferred locations at startup.

Or you could have a Storagefile member of a global variable called User Preferences. Still could be a singleton but doesn't really matter in this case.

For me complex defaults (dozens of different types of classes) should reside in their own "space" accessible to model.

However there may be preferences that are important to how a Job is setup so those preference need to be stored in the Job Object so when you open it in another user's application it works as intended.

Again it depends on your design.

RS Conley
+10  A: 

Calling it a global variable is technically correct but misleading.

It is a global constant -- global in scope but constant and therefore not bad in the sense that global variables are bad.

To show how global constants are common, safe and numerous, consider these examples of global constants:

  • Every class in your program
  • Every #define
  • Every enum
  • Almost every name declared by Cocoa (excluding rare global variables like NSApp).

The only time you should worry about global constants is when there names are too generic (they may pollute the global namespace). So don't use names that are likely to conflict with anything (always use a prefix and always make the name task-specific like NSKeyValueObservingOptionNew).

Matt Gallagher
+18  A: 

Just to be clear, the recommendation is to create immutable global variables instead of in-line string constants (hard to refactor and no compile-time checking) or #defines (no compile-time checking). Here's how you might do so...

in MyConstants.h:

extern NSString * const MyStringConstant;

in MyConstants.m:

NSString * const MyStringConstant = @"MyString";

then in any other .m file:

#import "MyConstants.h"

...
[someObject someMethodTakingAString:MyStringConstant];
...

This way, you gain compile-time checking that you haven't mis-spelled a string constant, you can check for pointer equality rather than string equality[1] in comparing your constants, and debugging is easier, since the constants have a run-time string value.

[1] In this use, you are essentially using the pointer values as the constants. It just so happens that those particular integers also point to strings that can be used in the debugger

Barry Wark
“const NSString” doesn’t really mean anything; constness would be disregarded by message sends anyway. String constants in Cocoa are generally declared <code>extern NSString * const NSFoo;</code>, meaning the <em>pointer</em> is read-only. The string objects are of course immutable.
Ahruman
Gah. Why can I use tags in an answer but not a comment?
Ahruman
Damn, if I don't look it up every time, I always get const pointers wrong. Thanks for the catch.And yeah, there should be code tags in answers too!
Barry Wark
What's the downfall in giving up const? it's any useful for a NSString? given that they're immutable regardless.
pablasso
Oh, i got my response from your answer here: http://goo.gl/tTFfI was feeling dirty casting every time :)
pablasso
Use backticks `\`` for code in comments (and in answers, actually), and stars `*` for emphasis.
jbrennan