Iphone 使用线程安全的单例初始化代码时,代码执行停止
为了利用全局变量和方法,我实现了Singleton作为一种健康的编码实践。在实施之前,我遵循了。首先,我没有使我的单线程安全,我实现了这个方法以及博客和苹果文档中提到的所有其他方法Iphone 使用线程安全的单例初始化代码时,代码执行停止,iphone,objective-c,ios,singleton,Iphone,Objective C,Ios,Singleton,为了利用全局变量和方法,我实现了Singleton作为一种健康的编码实践。在实施之前,我遵循了。首先,我没有使我的单线程安全,我实现了这个方法以及博客和苹果文档中提到的所有其他方法 + (SingletonClass *)sharedManager { static SingletonClass *sharedManager = nil; if (sharedManager == nil) { sharedManager = [[super allocWithZone:NULL
+ (SingletonClass *)sharedManager
{
static SingletonClass *sharedManager = nil;
if (sharedManager == nil) {
sharedManager = [[super allocWithZone:NULL] init];
}
return sharedManager;
}
在那之后,为了使单例线程安全,我对+(SingletonClass*)sharedManager
类做了如下更改,我的应用程序停止启动。我设置断点,观察到dispatch\u一旦被调用两次,代码就会停止执行
+(SingletonClass *)sharedManager
{
static SingletonClass *sharedManager = nil;
if (sharedManager !=nil)
{
return sharedManager;
}
static dispatch_once_t pred;
dispatch_once(&pred, ^{
sharedManager = [SingletonClass alloc];
sharedManager=[sharedManager init];
});
return sharedManager;
}
如果我删除这个线程安全的代码片段,并恢复到以前的代码,它工作正常,代码得到执行
请注意,我还查看了他在提问前提到的可能出现僵局的情况,但我无法找出问题所在。任何解释或解决方案都会对我有帮助。谢谢
编辑1:
如果有人想查看完整的代码,我已经为此创建了。请跟在那里。谢谢。您不需要顶部的复选框,如果
语句不存在,请去掉。dispatch\u once
保证在应用程序的生命周期内只执行一次块,因此第一次检查是冗余的
更多信息:
如果两个线程几乎同时调用<代码>共享管理器< /COD>两个线程,会发生什么情况。
线程1首先调用。它检查sharedManager=nil
,该值为false,因此它将继续执行一次调度
。在dispatch\u once
块中,它执行[SingletonClass alloc]
并将结果存储在sharedManager
中
现在,在线程1继续下一行之前,线程2出现并调用sharedManager
。线程2检查sharedManager=nil
,现在为真。因此它返回sharedManager
,然后调用方尝试使用sharedManager
。但此时,sharedManager
尚未完全初始化。那太糟糕了
只有在有一个完全初始化的对象将其设置为之前,才能设置sharedManager
。此外(正如Borrden指出的那样),您不需要sharedManager=nil
在顶部检查,因为一次调度
非常有效
+ (SingletonClass *)sharedManager {
static dispatch_once_t pred;
static SingletonClass *sharedManager;
dispatch_once(&pred, ^{
sharedManager = [[SingletonClass alloc] init];
});
return sharedManager;
}
现在,我看了你的要点,你的问题是:
+ (id)allocWithZone:(NSZone*)zone {
return [[self sharedManager] retain];
}
您的+[SingletonClass sharedManager]
方法在dispatch\u once
块中调用+[SingletonClass alloc]
。由于不重写alloc
,+[SingletonClass alloc]
调用+[SingletonClass allocWithZone:NULL]
。和+[SingletonClass allocWithZone:
方法调用+[SingletonClass sharedManager]
。在第二次调用sharedManager
时,您的程序挂起dispatch\u once
,因为您仍然在第一次调用dispatch\u once
时
最简单的修复方法是删除allocWithZone:
的实现。只需说明sharedManager
是获取SingletonClass
实例并继续前进的唯一受支持的方法
如果您想变得迟钝,让[[SingletonClass alloc]init]
返回singleton,即使重复执行,也很复杂。不要试图覆盖alloc
或allocWithZone:
。这样做:
static SingletonClass *sharedManager; // outside of any method
+ (SingletonClass *)sharedManager {
return sharedManager ? sharedManager : [[SingletonClass alloc] init];
}
- (id)init {
static dispatch_once_t once;
dispatch_once(&once, ^{
if (self = [super init]) {
// initialization here...
sharedManager = self;
}
});
self = sharedManager;
return self;
}
感谢您对代码的详细解释。。我编写了sharedManager=[[SingletonClass alloc]init]代码>在第一行中,然后根据我提到的bbum的答案将其分成两行。你说得对,问题出在别的地方。如果有人想查看完整代码,也会发布完整代码的链接。太好了。。现在工作。。感谢您花时间查看完整的代码。接受作为回答……值得补充的是:发送一次是很快的。至少和“零”检查一样快。不同的是,有人编写了一些非常聪明的代码来保证线程安全,而“nil”的检查则不是。在最坏的情况下,sharedSingleton可能会在编写代码时返回nil(如果第二个调用在sharedSingleton分配之前仍然为nil时进入,则运行的dispatch_一旦完成,dispatch_once将不执行任何操作,因为第一个dispatch_一旦完成,并且由于sharedSingleton不易失性,编译器会假定它仍然为nil并返回nil。