我的单例访问方法通常是一些变种:
static MyClass *gInstance = NULL;
+ (MyClass *)instance
{
@synchronized(self)
{
if (gInstance == NULL)
gInstance = [[self alloc] init];
}
return(gInstance);
}
我能做些什么来改善这一点呢?
我的单例访问方法通常是一些变种:
static MyClass *gInstance = NULL;
+ (MyClass *)instance
{
@synchronized(self)
{
if (gInstance == NULL)
gInstance = [[self alloc] init];
}
return(gInstance);
}
我能做些什么来改善这一点呢?
当前回答
编辑:这个实现在ARC中过时了。请看看我如何实现一个与ARC兼容的Objective-C单例?为了正确的执行。
我在其他答案中读到的所有初始化的实现都有一个共同的错误。
+ (void) initialize {
_instance = [[MySingletonClass alloc] init] // <----- Wrong!
}
+ (void) initialize {
if (self == [MySingletonClass class]){ // <----- Correct!
_instance = [[MySingletonClass alloc] init]
}
}
苹果文档建议你检查初始化块中的类类型。因为子类默认调用初始化。存在一种不明显的情况,即可以通过KVO间接创建子类。如果你在另一个类中添加以下行:
[[MySingletonClass getInstance] addObserver:self forKeyPath:@"foo" options:0 context:nil]
Objective-C将隐式地创建MySingletonClass的一个子类,导致第二次触发+initialize。
你可能认为你应该隐式地检查init块中重复的初始化,如下所示:
- (id) init { <----- Wrong!
if (_instance != nil) {
// Some hack
}
else {
// Do stuff
}
return self;
}
但你会搬起石头砸自己的脚;或者更糟糕的是,给其他开发者搬起石头砸自己的脚。
- (id) init { <----- Correct!
NSAssert(_instance == nil, @"Duplication initialization of singleton");
self = [super init];
if (self){
// Do stuff
}
return self;
}
TL, DR,这是我的实现
@implementation MySingletonClass
static MySingletonClass * _instance;
+ (void) initialize {
if (self == [MySingletonClass class]){
_instance = [[MySingletonClass alloc] init];
}
}
- (id) init {
ZAssert (_instance == nil, @"Duplication initialization of singleton");
self = [super init];
if (self) {
// Initialization
}
return self;
}
+ (id) getInstance {
return _instance;
}
@end
(用我们自己的断言宏替换ZAssert;或者只是NSAssert。)
其他回答
我通常使用的代码大致类似于Ben Hoffstein的回答(这也是我从维基百科上得到的)。我使用它的原因是Chris Hanson在他的评论中提到的。
然而,有时我需要将一个单例放入NIB中,在这种情况下,我使用以下方法:
@implementation Singleton
static Singleton *singleton = nil;
- (id)init {
static BOOL initialized = NO;
if (!initialized) {
self = [super init];
singleton = self;
initialized = YES;
}
return self;
}
+ (id)allocWithZone:(NSZone*)zone {
@synchronized (self) {
if (!singleton)
singleton = [super allocWithZone:zone];
}
return singleton;
}
+ (Singleton*)sharedSingleton {
if (!singleton)
[[Singleton alloc] init];
return singleton;
}
@end
我把-retain(等等)的实现留给读者,尽管在垃圾收集环境中您只需要上面的代码。
关于Objective-C中单例模式的深入讨论,请看这里:
在Objective-C中使用单例模式
公认的答案,虽然它编译,是不正确的。
+ (MySingleton*)sharedInstance
{
@synchronized(self) <-------- self does not exist at class scope
{
if (sharedInstance == nil)
sharedInstance = [[MySingleton alloc] init];
}
return sharedInstance;
}
根据苹果文档:
... 您可以采用类似的方法来同步相关类的类方法,使用class对象而不是self。
即使使用self工作,它不应该,这看起来像一个复制和粘贴错误对我来说。 类工厂方法的正确实现应该是:
+ (MySingleton*)getInstance
{
@synchronized([MySingleton class])
{
if (sharedInstance == nil)
sharedInstance = [[MySingleton alloc] init];
}
return sharedInstance;
}
这不应该是线程安全的,避免第一次调用后昂贵的锁定吗?
+ (MySingleton*)sharedInstance
{
if (sharedInstance == nil) {
@synchronized(self) {
if (sharedInstance == nil) {
sharedInstance = [[MySingleton alloc] init];
}
}
}
return (MySingleton *)sharedInstance;
}
关于单例宏代码的详细解释在Cocoa With Love博客上
http://cocoawithlove.com/2008/11/singletons-appdelegates-and-top-level.html。