gpt4 book ai didi

ios - iOS Objective C 中的单例不会阻止多个实例

转载 作者:可可西里 更新时间:2023-11-01 03:36:02 25 4
gpt4 key购买 nike

我知道有几个主题讨论这个问题,但没有一个能回答我的问题。

我已经像这样实现了我的单例类(意识到关于单例的争议):

+ (MyClass*) sharedInstance {
static MyClass *_sharedInstance = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_sharedInstance = [[MyClass alloc] init];
});
return _sharedInstance;
}

- (instancetype)init{
self = [super init];
if (self) {
//setup code
}
return self;
}

我尝试实例化一个不同的对象并将其与 sharedInstance 返回的带有“==”的对象进行比较,它们确实不同。

问题:

  1. 不应该创建多个单例类对象吗?这不是重点吗? Java 中的单例实现阻止了它。
  2. 如果是,怎么做?我应该创建一个设置方法并调用它而不是让 init 实现并执行它吗?
  3. 这是正确的实现方式吗?

最佳答案

您的观察是正确的,您在 Objective-C 中看到的许多“单例”模式根本不是单例,而是可以创建其他实例的“共享实例”模型。

在旧的 MRC 时代,Apple 曾经有示例代码来展示如何实现真正的单例。

您拥有的代码是 ARC 和线程安全单例的推荐模式,您只需将其放在 init 方法中:

- (instancetype) init
{
static MyClass *initedObject;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
initedObject = [super init];
});
return initedObject;
}

此代码将确保永远只有一个 MyClass 实例,无论有多少 [MyClass new][[MyClass alloc] init] 调用。

这就是您需要 做的全部,但您可以更进一步。首先,如果你希望有一个类方法来返回单例,它很简单:

+ (instancetype) singletonInstance
{
return [self new];
}

此方法最终调用 init 返回单例,如果需要则创建它。

如果 MyClass 实现了 NSCopying 那么你还需要实现 copyWithZone: - 这是 copy 的方法电话。因为你有一个单例,这真的很简单:

- (instancetype) copyWithZone:(NSZone *)zone
{
return self;
}

最后,在 Objective-C 中,分配新对象实例和初始化它的操作是不同的。上述方案确保只有一个 MyClass 实例被初始化和使用,但是对于每次调用 newalloc 都会分配另一个实例,然后迅速被 init 丢弃并被 ARC 清理。这有点浪费!

这很容易通过实现 allocWithZone: 来解决(就像上面的 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

关于ios - iOS Objective C 中的单例不会阻止多个实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30799696/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com