帮助理解类方法返回单例[重复]

问题描述

|                                                                                                                   这个问题已经在这里有了答案:                                                      

解决方法

        显然,单例背后的想法是仅创建一个实例。实现此目标的第一步是通过“ 0”行声明该类的静态实例。 第二步是检查单个实例是否已经创建,如果不是,则创建它,或者如果是,则返回现有的单个实例。但是,如果两个单独的线程试图在相同的确切时刻调用
+shared
方法,则第二步打开了潜在的问题。您不希望一个线程修改单个
sharedSingleton
变量,而另一个线程尝试对其进行检查,因为它可能产生意外的结果。 解决此问题的方法是使用“ 3”编译器指令来同步对括号之间指定的对象的访问。例如,假设
Game
类的单个共享实例具有一个名为
players
的实例变量,它是
Player
类的实例的
NSMutableArray
。假设
Game
类具有
-addPlayer:
方法,该方法将通过添加指定的播放器来修改
players
实例变量。重要的是,如果从多个线程中调用该方法,则一次只允许一个线程修改“ 5”数组。因此,该方法的实现可能如下所示:
- (void)addPlayer:(Player *)player {
   if (player == nil) return;
   @synchronized(players) {
      [players addObject:player];
   }
}
使用
@synchronized()
指令可确保一次只有一个线程可以访问
players
变量。如果一个线程试图在另一个线程当前正在访问它时,第一个线程必须等待,直到另一个线程完成。 尽管在谈论实例变量时它更直接,但在类本身的单一创建方法中如何实现相同类型的结果也许不太清楚。以下代码中
@synchronized(self)
行中的
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;
}
[编辑]:已更新。根据我不久前的测试(现在我刚刚对其进行了重新测试),以下各项似乎是等效的:
@implementation
外:
Game *sharedInstance;

@implementation Game
+ (Game *)sharedGame {
    @synchronized(self) {
        if (sharedInstance == nil) {
            sharedInstance = [[[self class] alloc] init];
        }
    }
    return sharedInstance;
}
@end
@implementation
static
外:
static Game *sharedInstance;

@implementation Game
+ (Game *)sharedGame {
    @synchronized(self) {
        if (sharedInstance == nil) {
            sharedInstance = [[[self class] alloc] init];
        }
    }
    return sharedInstance;
}
@end
@implementation
内部:
@implementation Game

static Game *sharedInstance;

+ (Game *)sharedGame {
    @synchronized(self) {
        if (sharedInstance == nil) {
            sharedInstance = [[[self class] alloc] init];
        }
    }
    return sharedInstance;
}
@end
+sharedGame
内部:
@implementation Game
+ (Game *)sharedGame {
    static Game *sharedInstance;
    @synchronized(self) {
        if (sharedInstance == nil) {
            sharedInstance = [[[self class] alloc] init];
        }
    }
    return sharedInstance;
}
@end
唯一的区别是,在第一个变体中,没有
static
关键字,在
gdb
中的File Statics下不会出现
sharedInstance
。显然,在最后一个变体中,the28ѭ方法之外不可见outside31ѭ。但是实际上,他们都保证当您呼叫ѭ35时,您会取回ѭ31,而ѭ31只会被创建一次。 (但是请注意,将需要采取进一步的预防措施,以防止某人使用诸如“ 38”之类的东西创建非单例实例)。     ,        逐行说明...
// 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;
}
    ,        我对Objective-C知之甚少,但是它似乎是一种用于获取Game *类型的单例副本的方法,并且旨在确保线程安全。 本质上,调用该方法将每次(无论哪个线程)都返回Game *的相同副本,并且直到第一次调用Game时才分配新的Game实例(称为延迟加载)。     ,        为了避免单例被复制,我还将覆盖“ mutableCopyWithZone:”和“ copyWithZone:”方法:
// copy cannot be done
- (Game *)copyWithZone:(NSZone *)zone {
    return self;
}
// mutablecopy cannot be done
- (Game *)mutableCopyWithZone:(NSZone *)zone {
    return [self copyWithZone:zone];
}
由于“ copy”和“ mutableCopy”(假设单例类不继承自覆盖了默认NSObject实现的另一个类),因此只需调用“ copyWithZone:”和“ mutableCopyWithZone:”即可,因此也不必覆盖它们。 为了避免其他开发人员使用“ init”或“ new”破坏单例模式,可以将这两种方法声明为不可用:
- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)new NS_UNAVAILABLE;
这样,编译器将不允许使用这两种方法,其他开发人员将被迫使用记录在案的方法来获取共享实例。 另一种(更严格的)技术是覆盖“ init”和“ new”并引发异常。     

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...