我想知道以下两种延迟初始化的解决方案是否正确。
我有一个类AppContext
应该包含对只存在一次的其他类的引用(避免将这些类中的每一个都设为单例)。假设这些其他类之一被称为ReferencedClass
. 话虽如此,我想以线程安全的方式使用默认值对引用进行延迟初始化。
之前已经讨论过,我已经阅读了很多关于它的内容,但我仍然不确定。除了个人喜好,我想知道的是:这两种解决方案是实现我想要的行为的正确方法吗?
解决方案1:最初我想这样实现它:
// Getter with lazy initialized default value
- (ReferencedClass *)referencedClass {
// Check if nil. If yes, wait for lock and check again after locking.
if (_referencedClass == nil) {
@synchronized(self) {
if (_referencedClass == nil) {
// Prevent _referencedClass pointing to partially initialized objects
ReferencedClass *temp = [[ReferencedClass alloc] init];
_referencedClass = temp;
}
}
}
return _referencedClass;
}
// Setter
- (void)setReferencedClass:(ReferencedClass *)referencedClass {
@synchronized(self) {
_referencedClass = referencedClass;
}
}
解决方案 2:然后我决定改用 GCD,所以我写了这个:
// Getter with lazy initialized default value
- (ReferencedClass *)referencedClass {
// Check if nil. If yes, wait for "lock" and check again after "locking".
if (_referencedClass == nil) {
dispatch_sync(syncDispatchQueue, ^{
if (_referencedClass == nil) {
// Prevent _referencedClass pointing to partially initialized objects
ReferencedClass *temp = [[ReferencedClass alloc] init];
_referencedClass = temp;
}
});
}
return _referencedClass;
}
// Setter
- (void)setReferencedClass:(ReferencedClass *)referencedClass {
dispatch_sync(syncDispatchQueue, ^{
_referencedClass = referencedClass;
});
}
当然,在某个地方(例如在init
-Method 中)我已经初始化了类似的syncDispatchQueue
东西:
syncDispatchQueue = dispatch_queue_create("com.stackoverflow.lazy", NULL);
这是正确的、线程安全的和无死锁的代码吗?我可以将双重检查锁定与-变量一起使用temp
吗?如果这种双重检查锁定不安全,如果我删除外部检查,我的代码在这两种情况下是否安全?我想是的,对吧?
首先十分感谢!
[旁注: 我知道 dispatch_once 并且有些人说(与Apple文档相反)它也可以与实例变量一起使用。不过,现在我想使用这两个选项之一。如果可能的话。]