我的单例访问方法通常是一些变种:
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);
}
我能做些什么来改善这一点呢?
当前回答
另一个选项是使用+(void)初始化方法。从文档中可以看到:
运行时将initialize发送给程序中的每个类一次,恰好在该类或从该类继承的任何类从程序中发送其第一条消息之前。(因此,如果类没有被使用,方法可能永远不会被调用。)运行时以线程安全的方式将初始化消息发送给类。超类在子类之前收到此消息。
所以你可以这样做:
static MySingleton *sharedSingleton;
+ (void)initialize
{
static BOOL initialized = NO;
if(!initialized)
{
initialized = YES;
sharedSingleton = [[MySingleton alloc] init];
}
}
其他回答
我的方法很简单:
static id instanceOfXXX = nil;
+ (id) sharedXXX
{
static volatile BOOL initialized = NO;
if (!initialized)
{
@synchronized([XXX class])
{
if (!initialized)
{
instanceOfXXX = [[XXX alloc] init];
initialized = YES;
}
}
}
return instanceOfXXX;
}
如果单例已经初始化,LOCK块将不会被输入。第二次检查if(!initialized)是为了确保当前线程获得LOCK时它还没有初始化。
这也适用于非垃圾收集环境。
@interface MySingleton : NSObject {
}
+(MySingleton *)sharedManager;
@end
@implementation MySingleton
static MySingleton *sharedMySingleton = nil;
+(MySingleton*)sharedManager {
@synchronized(self) {
if (sharedMySingleton == nil) {
[[self alloc] init]; // assignment not done here
}
}
return sharedMySingleton;
}
+(id)allocWithZone:(NSZone *)zone {
@synchronized(self) {
if (sharedMySingleton == nil) {
sharedMySingleton = [super allocWithZone:zone];
return sharedMySingleton; // assignment and return on first allocation
}
}
return nil; //on subsequent allocation attempts return nil
}
-(void)dealloc {
[super dealloc];
}
-(id)copyWithZone:(NSZone *)zone {
return self;
}
-(id)retain {
return self;
}
-(unsigned)retainCount {
return UINT_MAX; //denotes an object that cannot be release
}
-(void)release {
//do nothing
}
-(id)autorelease {
return self;
}
-(id)init {
self = [super init];
sharedMySingleton = self;
//initialize here
return self;
}
@end
我在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 origSel = @selector(sharedInstance);
SEL newSel = @selector(simpleSharedInstance);
Method origMethod = class_getClassMethod(self, origSel);
Method newMethod = class_getClassMethod(self, newSel);
method_exchangeImplementations(origMethod, newMethod);
}
}
return (MySingleton *)sharedInstance;
}
我只是想把这个放在这里,这样我就不会弄丢了。这个的优点是它可以在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;
}
static MyClass *sharedInst = nil; + (id)sharedInstance { @synchronize( self ) { if ( sharedInst == nil ) { /* sharedInst set up in init */ [[self alloc] init]; } } return sharedInst; } - (id)init { if ( sharedInst != nil ) { [NSException raise:NSInternalInconsistencyException format:@"[%@ %@] cannot be called; use +[%@ %@] instead"], NSStringFromClass([self class]), NSStringFromSelector(_cmd), NSStringFromClass([self class]), NSStringFromSelector(@selector(sharedInstance)"]; } else if ( self = [super init] ) { sharedInst = self; /* Whatever class specific here */ } return sharedInst; } /* These probably do nothing in a GC app. Keeps singleton as an actual singleton in a non CG app */ - (NSUInteger)retainCount { return NSUIntegerMax; } - (oneway void)release { } - (id)retain { return sharedInst; } - (id)autorelease { return sharedInst; }