在Objective-C中用init方法创build单例的安全方法

我想采用共享实例下一步的GCD方法,所以我创build了以下代码:

@implementation MyClass static id sharedInstance; #pragma mark Initialization + (instancetype)sharedInstance { static dispatch_once_t once; dispatch_once(&once, ^{ sharedInstance = [[self alloc] init]; }); return sharedInstance; } - (instancetype)init { if (sharedInstance) { return sharedInstance; } @synchronized(self) { self = [super init]; if (self) { sharedInstance = self; } return self; } } @end 

我假设sharedInstance方法似乎没问题,但我不确定有关的init方法。 创build这个的原因是,我不希望人们使用我的SDK,使用init方法,如果他们这样做…使其防弹。

而不是透明地将调用redirect到单向实现,这会给您的SDK用户造成非常混乱的行为,我build议不要根本调用init:

 + (instancetype)sharedInstance { static dispatch_once_t once; dispatch_once(&once, ^{ sharedInstance = [[self alloc] initPrivate]; }); return sharedInstance; } - (instancetype)init { @throw [NSException exceptionWithName:NSInternalInconsistencyException reason:@"..." userInfo:nil]; } - (instancetype)initPrivate { if (self = [super init]) { ... } return self; } 

我想提出解决你的问题的新方法。

你可以像这样在头文件中使用NS_UNAVAILABLE

 //Header file @interface MyClass : NSObject + (instancetype)sharedInstance - (instancetype)init NS_UNAVAILABLE; //... @end 

在这种情况下, init函数将无法从外部获得,不会被build议自动完成,并且您将能够正常使用执行文件中的init方法。

当你正在做一个单身人士的课程时,我build议你把new方法join到头文件中去:

 + (instancetype)new NS_UNAVAILABLE; 

还有一个老方法使得方法不可用(也可以在头文件中使用):

 - (instancetype) init __attribute__((unavailable("Use 'sharedInstance' instead of 'init' as this class is singleton."))); 

如果你想提示一些关于不可用的消息,可以使用这个。

一般的观点是,试图保护你的单身免受这种错误是毫无意义的。 无论谁调用[[LUIMain alloc] init]并创build一个单例,都会得到他们应得的。

而且你写的代码不是线程安全的。 如果我呼叫[[LUIMain alloc] init]而其他人调用sharedInstance ,则sharedInstance将返回与下一次呼叫不同的对象。 (在init方法中@synchronized (self)是没有意义的,因为第二个调用者会有不同的self)。