帮助理解返回单例的类方法

5lb*_*ass 12 singleton cocoa-touch objective-c singleton-methods ios

有人可以帮我理解下面的方法是做什么的吗?

+ (Game *) shared
{
    static Game *sharedSingleton;

    @synchronized(self)
    {
        if (!sharedSingleton)
        {
            sharedSingleton = [[Game alloc] init];
        }
    }

    return sharedSingleton;
}
Run Code Online (Sandbox Code Playgroud)

NSG*_*God 46

显然,单例背后的想法是只创建一个实例.实现这一目标的第一步是通过该行声明类的静态实例static Game *sharedSingleton;.

第二步是检查是否已经创建了单个实例,如果不是,则创建它,或者如果是,则返回现有的单个实例.但是,如果2个单独的线程尝试+shared在同一时刻调用该方法,则第二步将打开潜在的问题.您不希望一个线程修改单个sharedSingleton变量,而另一个线程正在尝试检查它,因为它可能会产生意外的结果.

此问题的解决方案是使用@synchronized()编译器指令来同步对括号之间指定的对象的访问.例如,假设Game该类的单个共享实例具有名为的实例变量players,该实例变量是类NSMutableArray的实例Player.假设Game该类有一个-addPlayer:方法,它将players通过添加指定的播放器来修改实例变量.重要的是,如果从多个线程调用该方法,则一次只允许一个线程修改该players数组.因此,该方法的实现可能如下所示:

- (void)addPlayer:(Player *)player {
   if (player == nil) return;
   @synchronized(players) {
      [players addObject:player];
   }
}
Run Code Online (Sandbox Code Playgroud)

使用该@synchronized()指令可确保一次只有一个线程可以访问该players变量.如果一个线程在另一个线程当前正在访问它时尝试,则第一个线程必须等到另一个线程完成.

虽然在谈论实例变量时它更直接,但是如何在类本身的单个创建方法中实现相同类型的结果可能不太清楚.将self@synchronized(self)下面的代码行基本上等同于Game类本身.通过在Game类上同步,它确保该sharedSingleton = [[Game alloc] init];行只被调用一次.

+ (Game *) shared
{
    static Game *sharedSingleton;

    @synchronized(self) // assures only one thread can call [Game shared] at a time
    {
        if (!sharedSingleton)
        {
            sharedSingleton = [[Game alloc] init];
        }
    }

    return sharedSingleton;
}
Run Code Online (Sandbox Code Playgroud)

[编辑]:更新.基于我的测试一段时间(我现在只是重新测试),以下所有看起来都是等效的:

外面@implementation:

Game *sharedInstance;

@implementation Game
+ (Game *)sharedGame {
    @synchronized(self) {
        if (sharedInstance == nil) {
            sharedInstance = [[[self class] alloc] init];
        }
    }
    return sharedInstance;
}
@end
Run Code Online (Sandbox Code Playgroud)

外面@implementation,static:

static Game *sharedInstance;

@implementation Game
+ (Game *)sharedGame {
    @synchronized(self) {
        if (sharedInstance == nil) {
            sharedInstance = [[[self class] alloc] init];
        }
    }
    return sharedInstance;
}
@end
Run Code Online (Sandbox Code Playgroud)

内部@implementation:

@implementation Game

static Game *sharedInstance;

+ (Game *)sharedGame {
    @synchronized(self) {
        if (sharedInstance == nil) {
            sharedInstance = [[[self class] alloc] init];
        }
    }
    return sharedInstance;
}
@end
Run Code Online (Sandbox Code Playgroud)

内部+sharedGame:

@implementation Game
+ (Game *)sharedGame {
    static Game *sharedInstance;
    @synchronized(self) {
        if (sharedInstance == nil) {
            sharedInstance = [[[self class] alloc] init];
        }
    }
    return sharedInstance;
}
@end
Run Code Online (Sandbox Code Playgroud)

唯一的区别是,在第一个变体中,没有static关键字,sharedInstance不会显示在File Statics下gdb.显然,在最后一个变体中,sharedInstance+sharedGame方法之外是不可见的.但实际上,他们都保证,当你打电话给[Game sharedInstance]你时,你会回来sharedInstance,并且sharedInstance只创造一次.(但是,请注意,需要采取进一步的预防措施来防止某人使用类似的东西创建非单例实例Game *game = [[Game alloc] init];).


Wol*_*urs 9

一行一行的解释......

// A static variable guarantees there's only 1 instance of it ever, 
// even accross multiple instances of the same class, this particular
// variable will store the class instance, so it can be returned whenever
// a client-class requests an instance of this class.
static Game *sharedSingleton;

// create a method that can always be called, even if there's no instance yet
// this method should create a new instance if there isn't one yet, otherwise
// return the existing instance
+ (Game *) shared  
{
    // synchronized makes sure only 1 client class can enter this method at any time, 
    // e.g. to prevent creating 2 instances whenever 2 client-classes try to 
    // access the following code from different threads.
    @synchronized(self)
    {
        // if the static variable is called for the first time, 
        // create an instance and return it, otherwise return the existing instance ...
        if (!sharedSingleton)
        {
            sharedSingleton = [[Game alloc] init];
        }
    }

    return sharedSingleton;
}
Run Code Online (Sandbox Code Playgroud)