Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/iphone/43.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Iphone 使用线程安全的单例初始化代码时,代码执行停止_Iphone_Objective C_Ios_Singleton - Fatal编程技术网

Iphone 使用线程安全的单例初始化代码时,代码执行停止

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

为了利用全局变量和方法,我实现了Singleton作为一种健康的编码实践。在实施之前,我遵循了。首先,我没有使我的单线程安全,我实现了这个方法以及博客和苹果文档中提到的所有其他方法

+ (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。