roh*_*tel 2 iphone singleton objective-c ios
为了利用全局变量和方法,我将Singleton实现为一种健康的编码实践.在实施之前我跟着Apple文档,john wordsworth博客.首先,我没有使我的单例线程安全,我实现了这个方法以及博客和Apple文档中提到的所有其他方法.
+ (SingletonClass *)sharedManager
{
static SingletonClass *sharedManager = nil;
if (sharedManager == nil) {
sharedManager = [[super allocWithZone:NULL] init];
}
return sharedManager;
}
Run Code Online (Sandbox Code Playgroud)
之后,为了使Singleton线程安全,我对+ (SingletonClass *)sharedManager类进行了更改,我的应用程序停止启动.我把断点和观察到的dispatch_once两次调用,然后代码停止执行.
+(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;
}
Run Code Online (Sandbox Code Playgroud)
如果我删除此线程安全代码片段并恢复到以前的代码,它工作正常,代码执行.
请注意,我也在这里查看了bbum的答案,他在提问之前提到了可能的死锁情况,但我无法弄清楚问题.任何解释或解决方案对我都有帮助.谢谢.
编辑1:
如果有人想要查看完整的代码,我已经为此创建了要点.请跟着那里.谢谢.
让我们考虑如果两个线程sharedManager几乎同时调用第二个版本会发生什么.
线程1首先调用.它检查sharedManager !=nil,这是错误的,所以它继续dispatch_once.在dispatch_once块中,它执行[SingletonClass alloc]并存储结果sharedManager.
现在,在线程1继续到下一行之前,线程2出现并调用sharedManager.线程2检查sharedManager !=nil,现在是真的.所以它返回sharedManager,然后调用者尝试使用sharedManager.但此时sharedManager尚未完全初始化.那很糟.
sharedManager在有完全初始化的对象将其设置为之前,您无法设置.另外(正如borrrden指出的那样),你不需要sharedManager !=nil在顶部检查,因为dispatch_once无论如何都非常有效.
+ (SingletonClass *)sharedManager {
static dispatch_once_t pred;
static SingletonClass *sharedManager;
dispatch_once(&pred, ^{
sharedManager = [[SingletonClass alloc] init];
});
return sharedManager;
}
Run Code Online (Sandbox Code Playgroud)
现在,我看了你的要点,你的问题就在这里:
+ (id)allocWithZone:(NSZone*)zone {
return [[self sharedManager] retain];
}
Run Code Online (Sandbox Code Playgroud)
您的+[SingletonClass sharedManager]方法+[SingletonClass alloc]在dispatch_once块中调用.由于您没有覆盖alloc,请+[SingletonClass alloc]致电+[SingletonClass allocWithZone:NULL].和+[SingletonClass allocWithZone:]方法调用+[SingletonClass sharedManager].在第二次通话中sharedManager,您的程序会挂起dispatch_once,因为您仍然在第一次通话中dispatch_once.
最简单的解决方法是删除您的实现allocWithZone:.只是文档sharedManager是唯一支持获取实例SingletonClass并继续前进的方法.
如果你想变钝并且让[[SingletonClass alloc] init]单身人士返回,即使你反复做,也很复杂.不要试图覆盖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;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
773 次 |
| 最近记录: |