我继承了一个看起来非常可疑的代码库,如果我是愚蠢的或者是所有错误的傻瓜,我就无法解决问题。这是要点:
在base.h中
@interface Base
{}
+(id)instance
@end
在base.m
+(id)instance
{
static dispatch_once_t pred = 0;
__strong static id me = nil;
dispatch_once( &pred, ^{ me = [[self alloc] init] });
return me;
}
在derived1.h
@interface Derived1 : Base {}
在derived2.h中
@interface Derived2 : Base {}
问题似乎是单例生成如下:
[[Derived2 instance] foo];
这肯定会设置" me
"永远属于Derived2
类型,所以如果我调用
[[Derived1 instance] bar];
这是竞争条件吗?或者static
在这里意味着什么略有不同?
答案 0 :(得分:3)
这不是竞争条件"在该术语的标准使用中,但您是正确的,因为首先调用[Base instance]
,[Derived1 instance]
或[Derived2 instance]
中的任何一个确定存储在唯一{{1}中的对象的类型变量。
me
的含义与C(++)中的含义完全相同。
解决方案是将static
中的声明更改为:
Base
并包含定义三次,每次一次:
+ (instancetype) instance;
这样,三个类中的每一个都有自己的方法和自己的静态变量+ (instancetype)instance
{
static dispatch_once_t pred = 0;
__strong static id me = nil;
dispatch_once( &pred, ^{ me = [[self alloc] init]; });
return me;
}
。 me
的使用,它告诉编译器instancetype
返回一个与它被调用的相同类型的对象(这是instance
族方法的默认值),改善了编译时类型检查。
HTH
答案 1 :(得分:1)
static
是一个C关键字。
作为两者,Objective-C和C ++或多或少只是C编程语言的插件,static
在所有三种语言中都是相同的。
是的,它在您的代码示例中是一种竞争条件。 这意味着您的代码将很好地编译,但如果Derived2没有实现方法栏(但Derived1会 - 为了编译器的缘故),那么您将在运行时遇到异常。
答案 2 :(得分:1)
是的,在这种情况下,static
变量在C和C ++中的行为相同(并且通过扩展名Obj-C和Obj-C ++)并且您的关注是正确的。
假设+instance
类方法未被覆盖,+[Derived1 instance]
和+[Derived2 instance]
将始终返回相同的实例,并且该实例的类型由所调用的确定第一
要使用此模式为每个子类提供单独的单例,每个子类必须覆盖+instance
并提供自己的实现。
注意:
+instance
。