我想在我的类中使用单例模式,它有一个带参数的私有init
,还有一个名为setup
的类函数,用于配置和创建共享示例,我的目标c代码是:
@interface MySingleton: NSObject
+ (MySingleton *)setup:(MyConfig *)config;
+ (MySingleton *)shared;
@property (readonly, strong, nonatomic) MyConfig *config;
@end
@implementation MySingleton
static MySingleton *sharedInstance = nil;
+ (MySingleton *)setup:(MyConfig *)config {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] initWithConfig:config];
});
// Some other stuff here
return sharedInstance;
}
+ (MySingleton *)shared {
if (sharedInstance == nil) {
NSLog(@"error: shared called before setup");
}
return sharedInstance;
}
- (instancetype)initWithConfig:(RVConfig *)config {
self = [super init];
if (self) {
_config = config;
}
return self;
}
@end
我被斯威夫特困住了:
class Asteroid {
var config: ASTConfig? // This actually should be read-only
class func setup(config: ASTConfig) -> Asteroid {
struct Static {
static let instance : Asteroid = Asteroid(config: config)
}
return Static.instance
}
class var shared: Asteroid? {
// ???
}
private init(config: ASTConfig) {
self.config = config
}
}
我想我还在用objective-c的方式思考,用swift也想不出来。有什么帮助吗?
6条答案
按热度按时间ckocjqey1#
我有一个稍微不同的解决方案。它依赖于
1.静态变量被延迟初始化
1.使用Config结构存储初始化参数
1.在init中使用fatalError强制执行setup调用(如果在访问单例之前没有调用setup调用)
。
要使用此功能,请使用以下命令对其进行设置
(显然,如果需要,可以通过扩展MySingleton.config结构使用多个参数)
然后要访问单例对象,可以使用
我并不热衷于使用单独的setup结构体,但我喜欢它保持接近推荐的单例模式。将setup结构体保持在单例中可以保持相当干净。
注意-共享对象是一个单例对象。在后台,swift使用dispatchOnce来保证这一点。但是,没有什么可以阻止您使用来自不同线程的不同配置多次调用setup。
目前,第一次调用shared将"锁定"设置。
如果您想在第一次调用setup后锁定所有内容,则只需调用
设置中
o4hqfura2#
Objective-C代码的字面翻译可能是:
或者,在Swift 1.2中,您可以删除
Static
结构体并稍微简化setup
:这真的不是单体。(我想你知道这一点,但我提到这一点是为了将来的读者)。通常单例可以在第一次使用它们的任何地方和任何时候被示例化。这是一个场景,它只在一个特定的地方被示例化和配置,在你尝试在其他地方使用它之前,你必须小心地做到这一点。这是一个非常奇怪的方法。我们失去了一些单例功能,但是仍然遭受所有传统的单例限制。
很明显,如果你不介意的话,那就没问题。但是如果你有其他选择的话,我会跳出来两个:
1.使其成为真实的的单例:你可以通过将
ASTConfig
的示例化移到init
方法中来完成这一点(消除了在使用sharedInstance
之前必须调用setup
的依赖性)。然后你可以退出setup
,像往常一样使用你的单例。最终的实现也得到了极大的简化。它被简化为如下所示:很明显,我怀疑问题出在
ASTConfig
对象的细节上,但是如果你能做一个合适的单例实现,你会发现这要简单得多(特别是在Swift 1.2中)。上面的内容消除了setup
与sharedInstance
的问题。消除了私有全局。只是简单了很多。话虽如此,我认为您有令人信服的理由这样做,也许有一些关键的理由,为什么您必须将
ASTConfig
对象传递给setup
方法,而不是自己在Asteroid
类的init
中示例化它。我只是觉得有必要指出,一个合适的单例将是非常可取的(既简化了实现,又消除了理论上的竞态条件)。
1.完全放弃单例模式:假设使用正确的单例(如上所述)是不可能的,那么下一个问题是是否应该放弃单例的任何剩余外观,只是在当前调用
setup
的地方示例化一个简单的Asteroid
,然后不依赖于sharedInstance
,而是将它传递给真正需要它的对象。你已经预先指定了你将要手动
setup
Asteroid
,所以让我们正式化这种关系,并消除许多单例引入的结构缺陷(参见What's Alternative to Singleton或google“singletons are evil”)。不要误解我的意思。我假设您有令人信服的理由来这样做,如果当前的实现对您有效,那也没关系。但这是一种非常奇怪的方法,在这种方法中,您会被单例的理论责任所拖累,而不会享受到所有的好处。
rsl1atfo3#
你可以定义一个单例,它最初带有一个或多个参数,方法是创建
static sharedInstance
属性private
并使用一个方法返回现有示例(可选地更改其属性值),或者初始化一个新示例并设置其属性值。您可以通过将
config
属性的setter定义为private
,使其成为只读属性......但是
shared(config:)
的调用者仍然可以更改配置。为了防止这种情况,您需要将shared(config:)
设置为一个抛出方法:a14dhokn4#
这似乎是在swift中实现单例的最简单方法:
其用法为:
Source和Source
mrwjdhj35#
不同答案的简化版本;但是没有任何强制展开,
shared
不是func
,而是有可能是config
。它不需要比这个更复杂,它在Swift 5中运行良好:当然,如果您只需要设置 * 一个 * 参数,那么您可以删除
ParameterSingletonConfig
并将其替换为String
a2mppw5e6#