Obviously, the idea of a single element is to create only one instance. The first step in achieving this is to declare a static instance of the class through the string static Game *sharedSingleton; .
The second step is to check whether one instance has already been created, and if not, create it or return it to return an existing separate instance. However, this second step opens up potential problems if two separate threads try to call the +shared method at the same time. You would not want one thread to modify a single sharedSingleton variable, while another thread is trying to examine it, as this may lead to unexpected results.
The solution to this problem is to use the @synchronized() compiler directive to synchronize access to the object indicated in parentheses. For example, let's say that this single generic instance of the Game class has an instance variable called players , which is an NSMutableArray instances of the Player class. Let's say the Game class had the -addPlayer: method, which would modify the players instance variable by adding the specified player. It is important that if this method were called from several threads, then only one thread was allowed to modify the players array at a time. Thus, the implementation of this method may look something like this:
- (void)addPlayer:(Player *)player { if (player == nil) return; @synchronized(players) { [players addObject:player]; } }
Using the @synchronized() directive ensures that only one thread can access the players variable at a time. If one thread is trying to use another thread at the moment, the first thread must wait for the other thread to finish.
Although this is more straightforward when you talk about an instance variable, it may be less clear how to achieve the same result in the same method of creating the class itself. The line self in the line @synchronized(self) in the following code is basically equal to the class Game . By synchronizing with the Game class, it ensures that the string sharedSingleton = [[Game alloc] init]; only called once.
+ (Game *) shared { static Game *sharedSingleton; @synchronized(self)
[EDIT]: updated. Based on my tests some time ago (and I just re-tested it now), they all look equivalent:
External @implementation :
Game *sharedInstance; @implementation Game + (Game *)sharedGame { @synchronized(self) { if (sharedInstance == nil) { sharedInstance = [[[self class] alloc] init]; } } return sharedInstance; } @end
Outside of @implementation , static :
static Game *sharedInstance; @implementation Game + (Game *)sharedGame { @synchronized(self) { if (sharedInstance == nil) { sharedInstance = [[[self class] alloc] init]; } } return sharedInstance; } @end
Inside @implementation :
@implementation Game static Game *sharedInstance; + (Game *)sharedGame { @synchronized(self) { if (sharedInstance == nil) { sharedInstance = [[[self class] alloc] init]; } } return sharedInstance; } @end
Inside +sharedGame :
@implementation Game + (Game *)sharedGame { static Game *sharedInstance; @synchronized(self) { if (sharedInstance == nil) { sharedInstance = [[[self class] alloc] init]; } } return sharedInstance; } @end
The only difference is that in the first version, without the static , sharedInstance not displayed in the "File statistics" section in gdb . And, obviously, in the latter version, sharedInstance not displayed outside the +sharedGame method. But almost all of them claim that when you call [Game sharedInstance] , you will return sharedInstance and that sharedInstance is created only once. (Note, however, that further precautions are needed so that someone cannot create an instance other than a single one using something like Game *game = [[Game alloc] init]; ).