Objective-C中的单例,与ARC和线程安全兼容
我希望有一个线程安全、ARC兼容的单例,但在我看来,我发现的最常见的单例示例,粘贴在这里的示例:Objective-C中的单例,与ARC和线程安全兼容,objective-c,singleton,automatic-ref-counting,Objective C,Singleton,Automatic Ref Counting,我希望有一个线程安全、ARC兼容的单例,但在我看来,我发现的最常见的单例示例,粘贴在这里的示例: + (MyClass *)sharedInstance { static MyClass *sharedInstance = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedInstance = [[self alloc] init];
+ (MyClass *)sharedInstance
{
static MyClass *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
// Do any other initialisation stuff here
});
return sharedInstance;
}
不会阻止其他开发人员调用[[MyClass alloc]init]并重写所需的流。
处理它的正确方法是什么(除了在init中抛出异常)?使用Borg模式而不是Singleton模式:允许类的多个实例化,并使实例共享相同的静态
// Shared data
static NSDictionary *sharedData = nil;
+ (void) initialize {
// Initialize shared data
sharedData = [[NSDictionary alloc] init];
}
- (id) init {
self = [super init];
if (self) {
self.data = sharedData;
}
}
这样,客户端可以任意使用静态
getInstance
方法或init
方法,并接收共享相同状态的对象。他们甚至不需要知道它是一个单例。使用博格模式而不是单例模式:允许类的多个实例化,并让实例共享相同的静态
// Shared data
static NSDictionary *sharedData = nil;
+ (void) initialize {
// Initialize shared data
sharedData = [[NSDictionary alloc] init];
}
- (id) init {
self = [super init];
if (self) {
self.data = sharedData;
}
}
这样,客户端可以任意使用静态
getInstance
方法或init
方法,并接收共享相同状态的对象。他们甚至不需要知道它是一个单例。您还必须重写+alloc
方法,以避免分配多个单例实例
编辑#3:好吧,我真的知道官方文档中关于覆盖+alloc
方法的说法,但是要实现所要求的好处,没有办法避免它。就个人而言,我不同意这样做,但它可以提供预期的结果
是这样的:
static MyClass *_sharedInstance = nil;
static BOOL _bypassAllocMethod = TRUE;
+ (id)sharedInstance {
@synchronized([MyClass class]) {
if (_sharedInstance == nil) {
_sharedInstance = [[MyClass alloc] init];
}
}
return _sharedInstance;
}
+ (id)alloc {
@synchronized([MyClass class]) {
_bypassAllocMethod = FALSE; // EDIT #2
if (_sharedInstance == nil) {
_sharedInstance = [super alloc];
return _sharedInstance;
} else {
// EDIT #1 : you could throw an exception here to avoid the double allocation of the singleton class
@throw [NSException exceptionWithName:[NSString stringWithFormat:@"<%@: %p> Double allocation issue", [_sharedInstance class], _sharedInstance] reason:@"You cannot allocate the singeton class twice or more." userInfo:nil];
}
}
return nil;
}
// EDIT #2 : the init method
- (id)init {
if (_bypassAllocMethod)
@throw [NSException exceptionWithName:@"invalid allocation" reason:@"invalid allocation" userInfo:nil];
if (self = [super init]) {
}
return self
}
静态MyClass*\u sharedInstance=nil;
静态布尔_bypassAllocMethod=TRUE;
+(id)共享状态{
@已同步([MyClass]){
如果(_sharedInstance==nil){
_sharedInstance=[[MyClass alloc]init];
}
}
返回-共享状态;
}
+(id)alloc{
@已同步([MyClass]){
_bypassAllocMethod=FALSE;//编辑#2
如果(_sharedInstance==nil){
_sharedInstance=[super alloc];
返回-共享状态;
}否则{
//编辑#1:您可以在这里抛出一个异常,以避免singleton类的双重分配
@抛出[NSException Exception WithName:[NSString stringWithFormat:@“双重分配问题”,[U sharedInstance类],[U sharedInstance]原因:@“您不能分配Sington类两次或更多次。”用户信息:nil];
}
}
返回零;
}
//编辑#2:init方法
-(id)init{
如果(_bypassAllocMethod)
@抛出[NSException Exception With Name:@“无效分配”原因:@“无效分配”用户信息:nil];
if(self=[super init]){
}
回归自我
}
编辑#1 您不一定需要在这里抛出异常,但对于以错误方式使用您的类的开发人员来说,这比发回一个简单的
nil
指针更直观
编辑#2
我添加了一个简单的技巧,以避免开发人员实例化类以绕过修改的
+alloc
方法,在这种情况下,分配将正常工作,但-init
将引发异常。您还必须重写+alloc
方法,以避免分配多个单例实例
编辑#3:好吧,我真的知道官方文档中关于覆盖+alloc
方法的说法,但是要实现所要求的好处,没有办法避免它。就个人而言,我不同意这样做,但它可以提供预期的结果
是这样的:
static MyClass *_sharedInstance = nil;
static BOOL _bypassAllocMethod = TRUE;
+ (id)sharedInstance {
@synchronized([MyClass class]) {
if (_sharedInstance == nil) {
_sharedInstance = [[MyClass alloc] init];
}
}
return _sharedInstance;
}
+ (id)alloc {
@synchronized([MyClass class]) {
_bypassAllocMethod = FALSE; // EDIT #2
if (_sharedInstance == nil) {
_sharedInstance = [super alloc];
return _sharedInstance;
} else {
// EDIT #1 : you could throw an exception here to avoid the double allocation of the singleton class
@throw [NSException exceptionWithName:[NSString stringWithFormat:@"<%@: %p> Double allocation issue", [_sharedInstance class], _sharedInstance] reason:@"You cannot allocate the singeton class twice or more." userInfo:nil];
}
}
return nil;
}
// EDIT #2 : the init method
- (id)init {
if (_bypassAllocMethod)
@throw [NSException exceptionWithName:@"invalid allocation" reason:@"invalid allocation" userInfo:nil];
if (self = [super init]) {
}
return self
}
静态MyClass*\u sharedInstance=nil;
静态布尔_bypassAllocMethod=TRUE;
+(id)共享状态{
@已同步([MyClass]){
如果(_sharedInstance==nil){
_sharedInstance=[[MyClass alloc]init];
}
}
返回-共享状态;
}
+(id)alloc{
@已同步([MyClass]){
_bypassAllocMethod=FALSE;//编辑#2
如果(_sharedInstance==nil){
_sharedInstance=[super alloc];
返回-共享状态;
}否则{
//编辑#1:您可以在这里抛出一个异常,以避免singleton类的双重分配
@抛出[NSException Exception WithName:[NSString stringWithFormat:@“双重分配问题”,[U sharedInstance类],[U sharedInstance]原因:@“您不能分配Sington类两次或更多次。”用户信息:nil];
}
}
返回零;
}
//编辑#2:init方法
-(id)init{
如果(_bypassAllocMethod)
@抛出[NSException Exception With Name:@“无效分配”原因:@“无效分配”用户信息:nil];
if(self=[super init]){
}
回归自我
}
编辑#1 您不一定需要在这里抛出异常,但对于以错误方式使用您的类的开发人员来说,这比发回一个简单的
nil
指针更直观
编辑#2
我添加了一个简单的技巧,以避免开发人员实例化类以绕过修改的
+alloc
方法,在这种情况下,分配将正常工作,但-init
将引发异常。将实例转换为类方法,并将类对象用作单例
例如,您有一个这样的单例类
@interface MySingleton {
int count;
}
+ (MySingleton *)sharedInstance;
- (int)getNext;
@end
我建议你把它改成
@interface MySingleton
+ (int)getNext;
@end
在迈辛格尔顿
static int count;
然后你可以像这样使用它
[MySingleton getNext];
或
编辑 我只想指出,对于单例模式已经有很多ObjC实现了
简单的谷歌搜索就能找到它们。一切都考虑到了。(比我预期的要多得多)将实例转换为类方法,并使用类对象作为单例 例如,您有一个这样的单例类
@interface MySingleton {
int count;
}
+ (MySingleton *)sharedInstance;
- (int)getNext;
@end
我建议你改变一下