Here is a global variable:
I’ll call this a zeroth-order global, on the premise that I need to talk to exactly zero objects (including classes) to gain access to this object.
Next, let’s look at a singleton:
[Wizard sharedWizard]; //hope he's not busy
I’ll call this a first-order global, as we need to ask the class for it (1 step) to gain access to it.
Now, here’s a second-order global:
MyAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
(I use UIApplication here because I see this most frequently in Cocoa Touch code, but the pattern applies equally to Cocoa.)
And here’s a third-order global:
Wizard *wizard = [appDelegate wizard];
I need to (1) ask the UIApplication class for the application object, (2) ask that for its delegate, and (3) ask that for the wizard. (Assume here that
wizard is a property, not a factory method that creates Wizards on the fly.)
None of these is any less global. If I can get to it from anywhere in the program without knowing about it directly, it is global.
Therefore, all the problems of globals apply:
- What if two threads want to use the same Wizard?
- What if the Wizard has a delegate of its own, and I have two objects that want to be its delegate?
- What if the Wizard keeps internal state that may be corrupted by multiple objects trying to use it? (Nothing should have to worry about this outside of the Wizard itself.)
Your application’s objects form a graph. It should not be a complex one like this:
Whenever you have paths bouncing around off of other objects like that, that’s a problem. The red arrows in the problem graph show where you violate the Law of Demeter.
Your object graph should, instead, be straightforward:
Note that each of your controllers should own—or, if you prefer, hire—a Wizard all to itself. This eliminates contention between objects and reduces the likelihood of contention between threads (assuming each of the owning objects is supposed to only work on a single thread and not juggle multiple threads).
If contention is not a problem and you have a good reason why there should be only one Wizard, such as memory pressure or union regulations, then use a singleton. But use a real singleton, and only when necessary, and beware of singletons in disguise.