您的观察是正确的,您在 Objective-C 中看到的许多“单例”模式根本不是单例,而是可以创建其他实例的“共享实例”模型。
在过去的 MRC 时代,Apple 曾经有示例代码来展示如何实现真正的单例。
您拥有的代码是 ARC 和线程安全单例的推荐模式,您只需将其放在init
method:
- (instancetype) init
{
static MyClass *initedObject;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
initedObject = [super init];
});
return initedObject;
}
这段代码将确保只有一个实例MyClass
无论有多少[MyClass new]
or [[MyClass alloc] init]
已拨打电话。
这就是你的全部need要做,但你可以走得更远。首先,如果您希望有一个类方法来返回单例,那么很简单:
+ (instancetype) singletonInstance
{
return [self new];
}
该方法最终调用init
它返回单例,并在需要时创建它。
If MyClass
实施NSCopying
那么你还需要实施copyWithZone:
- 这是方法copy
来电。由于您有一个单身人士,这非常简单:
- (instancetype) copyWithZone:(NSZone *)zone
{
return self;
}
最后,在 Objective-C 中,分配新对象实例和初始化它的操作是不同的。上述方案确保只有一个实例MyClass
已初始化并使用,但是对于每次调用new
or alloc
分配另一个实例,然后立即丢弃init
并由 ARC 清理。这有点浪费了!
这可以通过实施轻松解决allocWithZone:
(like copy
上面这个是方法alloc
实际上最终调用了)遵循与init
:
+ (instancetype) allocWithZone:(NSZone *)zone
{
static MyClass *allocatedObject;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
allocatedObject = [super allocWithZone:zone];
});
return allocatedObject;
}
第一次创建实例时allocWithZone:
将分配它,然后init
将初始化它,所有后续调用将返回已经存在的对象。没有丢弃不需要的分配。
就是这样,一个真正的单身人士,并不比常见的假单身人士难。
HTH