编辑
我在顶部包括了这个,在下面你可以看到我的历史原始问题和实施。但是我认为我找到了提供没有锁定开销的 sharedInstance 方法的最佳方法,我很想听听对此的潜在担忧:
// Volatile to make sure we are not foiled by CPU caches
static volatile ALBackendRequestManager *sharedInstance;
// There's no need to call this directly, as method swizzling in sharedInstance
// means this will get called after the singleton is initialized.
+ (MySingleton *)simpleSharedInstance
{
return (MySingleton *)sharedInstance;
}
+ (MySingleton*)sharedInstance
{
@synchronized(self)
{
if (sharedInstance == nil)
{
sharedInstance = [[MySingleton alloc] init];
// Replace expensive thread-safe method
// with the simpler one that just returns the allocated instance.
SEL orig = @selector(sharedInstance);
SEL new = @selector(simpleSharedInstance);
Method origMethod = class_getClassMethod(self, orig);
Method newMethod = class_getClassMethod(self, new);
method_exchangeImplementations(origMethod, newMethod);
}
}
return (MySingleton *)sharedInstance;
}
以及围绕初始化的历史讨论:
我现在看到原始代码实际上很像我的(如下),除了检查锁外的实例。
虽然新的 + (void) 初始化方法很有趣,但我不确定我是否更喜欢这个。现在似乎要获得一个单例实例,您现在必须始终调用:
MySingleton instance = [[MySingleton alloc] init];
这不正确吗?这感觉很奇怪,如果对初始化的调用已经为您锁定,效率会更高吗?对于这个用例,双锁方法似乎可以正常工作,同时也避免了锁定(我认为可能会以双重分配为代价,因为多个线程可能会通过 if)。
另一件看起来很奇怪的事情,如果初始化方法真的很受欢迎,为什么我们在其他地方看不到呢?Objective-C 已经存在了很长时间,我对与几乎所有已发布示例不同的基本机制持谨慎态度。
我目前使用的代码(这反映了我在其他地方看到的,包括这个答案):
+ (MySingleton *)sharedInstance
{
@synchronized(self)
{
if (sharedInstance == nil)
sharedInstance = [[MySingleton alloc] init];
}
return sharedInstance;
}
+ (id)allocWithZone:(NSZone *)zone
{
@synchronized(self)
{
if (sharedInstance == nil)
{
sharedInstance = [super allocWithZone:zone];
return sharedInstance; // assignment and return on first allocation
}
}
return nil; // on subsequent allocation attempts return nil
}