我的单例访问方法通常是一些变种:
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);
}
我能做些什么来改善这一点呢?
当前回答
这是我放在一起的一个宏:
http://github.com/cjhanson/Objective-C-Optimized-Singleton
它基于马特·加拉格尔的作品 但是将实现改为使用谷歌的Dave MacLachlan所描述的方法swizzling。
我欢迎评论/贡献。
其他回答
由于Kendall发布了一个线程安全的单例,试图避免锁定成本,我想我也会抛出一个:
#import <libkern/OSAtomic.h>
static void * volatile sharedInstance = nil;
+ (className *) sharedInstance {
while (!sharedInstance) {
className *temp = [[self alloc] init];
if(!OSAtomicCompareAndSwapPtrBarrier(0x0, temp, &sharedInstance)) {
[temp release];
}
}
return sharedInstance;
}
好吧,让我来解释一下这是怎么回事:
Fast case: In normal execution sharedInstance has already been set, so the while loop is never executed and the function returns after simply testing for the variable's existence; Slow case: If sharedInstance doesn't exist, then an instance is allocated and copied into it using a Compare And Swap ('CAS'); Contended case: If two threads both attempt to call sharedInstance at the same time AND sharedInstance doesn't exist at the same time then they will both initialize new instances of the singleton and attempt to CAS it into position. Whichever one wins the CAS returns immediately, whichever one loses releases the instance it just allocated and returns the (now set) sharedInstance. The single OSAtomicCompareAndSwapPtrBarrier acts as both a write barrier for the setting thread and a read barrier from the testing thread.
我只是想把这个放在这里,这样我就不会弄丢了。这个的优点是它可以在InterfaceBuilder中使用,这是一个巨大的优势。这是我问的另一个问题:
static Server *instance;
+ (Server *)instance { return instance; }
+ (id)hiddenAlloc
{
return [super alloc];
}
+ (id)alloc
{
return [[self instance] retain];
}
+ (void)initialize
{
static BOOL initialized = NO;
if(!initialized)
{
initialized = YES;
instance = [[Server hiddenAlloc] init];
}
}
- (id) init
{
if (instance)
return self;
self = [super init];
if (self != nil) {
// whatever
}
return self;
}
对于Objective C类方法,我们可以避免以通常的方式使用单例模式,如下所示:
[[Librarian sharedInstance] openLibrary]
to:
[Librarian openLibrary]
通过将类包装到另一个只有类方法的类中,这样就不会意外地创建重复的实例,因为我们没有创建任何实例!
我在这里写了一篇更详细的博客:)
你不想在self上同步…因为self对象还不存在!最终锁定一个临时id值。你想要确保没有其他人可以运行类方法(sharedInstance, alloc, allocWithZone:等),所以你需要在类对象上同步:
@implementation MYSingleton
static MYSingleton * sharedInstance = nil;
+( id )sharedInstance {
@synchronized( [ MYSingleton class ] ) {
if( sharedInstance == nil )
sharedInstance = [ [ MYSingleton alloc ] init ];
}
return sharedInstance;
}
+( id )allocWithZone:( NSZone * )zone {
@synchronized( [ MYSingleton class ] ) {
if( sharedInstance == nil )
sharedInstance = [ super allocWithZone:zone ];
}
return sharedInstance;
}
-( id )init {
@synchronized( [ MYSingleton class ] ) {
self = [ super init ];
if( self != nil ) {
// Insert initialization code here
}
return self;
}
}
@end
关于单例宏代码的详细解释在Cocoa With Love博客上
http://cocoawithlove.com/2008/11/singletons-appdelegates-and-top-level.html。