- Java 双重比较
- java - 比较器与 Apache BeanComparator
- Objective-C 完成 block 导致额外的方法调用?
- database - RESTful URI 是否应该公开数据库主键?
我想创建一个没有全局访问权限的 Swift 单例。我想要创建的模式是确保始终只存在一个类的实例,但不应通过通常的全局 MyClass.shared
访问此类。句法。这样做的原因是我希望这个类可以完全和正确地测试(这对于全局单例来说是不可能的)。然后我将使用依赖注入(inject)将单个实例从 viewcontroller 传递到 viewcontroller。因此,无需全局静态实例即可解决“访问”问题。
我能做的基本上就是什么都不做。只需创建一个普通类并相信所有开发人员的纪律,不要一次又一次地实例化此类,而仅将其作为依赖项注入(inject)。但我宁愿有一些编译器强制模式来禁止这种情况。
所以要求是:
我第一次尝试解决这个问题是这样的:
class WebService {
private static var instances = 0
init() {
assertSingletonInstance()
}
private func assertSingletonInstance() {
#if DEBUG
if UserDefaults.standard.bool(forKey: UserDefaultsKeys.isUnitTestRunning.rawValue) == false {
WebService.instances += 1
assert(WebService.instances == 1, "Do not create multiple instances of this class. Get it thru the shared dependencies in your module.")
}
#endif
}
}
备注:在启动期间传递参数会创建一个用户默认值,可以在运行时检查该值。这就是我如何知道当前运行是一个单元测试。
通常这种模式效果很好。我唯一的问题是——我必须为每个可能的单例一遍又一遍地复制这段代码。这不好。我更喜欢可重用的解决方案。
一个解决方案是创建协议(protocol)扩展:
protocol Singleton {
static var instances: Int { get set }
func assertSingletonInstance()
}
extension Singleton {
// Call this assertion in init() to check for multiple instances of one type.
func assertSingletonInstance() {
if UserDefaults.standard.bool(forKey: UserDefaultsKeys.isUnitTestRunning.rawValue) == false {
Self.instances += 1
assert(Self.instances == 1, "Do not create multiple instances of this class. Get it thru the shared dependencies in your module.")
}
#endif
}
}
然后这样使用:
class WebService: Singleton {)
static var instances = 0
init() {
assertSingletonInstance()
}
}
这种方法的问题是 instances
变量不是 private
.因此有人可以在实例化类之前将此变量设置为 0,这样检查将不再有效。
另一个尝试是 Singleton
基类。在本例中为 private static var instances
可以使用。
class Singleton {
private static var instances = 0
required init() {
assertSingletonInstance()
}
private func assertSingletonInstance() {
#if DEBUG
if UserDefaults.standard.bool(forKey: UserDefaultsKeys.isUnitTestRunning.rawValue) == false {
Singleton.instances += 1
assert(Singleton.instances == 1, "Do not create multiple instances of this class. Get it thru the shared dependencies in your module.")
}
#endif
}
}
这种方法的问题是 - 它不起作用。递增 Singleton.instance
将 static instances
加 1的 Singleton
键入而不是派生自 Singleton
的类基类。
现在我要么什么都不做,要么依赖所有开发人员的纪律和理解,要么至少使用协议(protocol)扩展 internal
或 public
使用权。
可以找到示例实现 here .
也许有人有更好的想法来真正干净地解决这个问题。我感谢任何提示或有关它的讨论。谢谢。
最佳答案
您可以使用原子标志(用于线程安全)将单例标记为已实例化:
class Singleton {
static private var hasInstance = atomic_flag()
init() {
// use precondition() instead of assert() if you want the crashes to happen in Release builds too
assert(!atomic_flag_test_and_set(&type(of: self).hasInstance), "Singleton here, don't instantiate me more than once!!!")
}
deinit {
atomic_flag_clear(&type(of: self).hasInstance)
}
}
您在 init
中将单例标记为已分配,并在 deinit
中重置标志。这允许你一方面只有一个实例(如果原始实例没有被释放),另一方面有多个实例,只要它们不重叠。
应用程序代码:假设您将在某处保留对注入(inject)下游的单例的引用,那么永远不应调用 deinit
,这只会导致一种可能的分配。
单元测试代码:如果单元测试正确地进行了清理(被测试的单例在每次测试后被释放),那么在某个时间点将只有一个活的实例,它赢了'触发断言失败。
关于Swift - 没有全局访问权限的单例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52482779/
我正在使用 Gunicorn 为 Django 应用程序提供服务,它工作正常,直到我将其超时时间从 30 秒更改为 900000 秒,我不得不这样做,因为我有一个用例需要上传和处理一个巨大的文件(过程
我有一个带有非常基本的管道的Jenkinsfile,它可以旋转docker容器: pipeline { agent { dockerfile { args '-u root' } } stag
在学习 MEAN 堆栈的过程中,我遇到了一个问题。每当我尝试使用 Passport 验证方法时,它都不会返回任何响应。我总是收到“localhost没有发送任何数据。ERR_EMPTY_RESPONS
在当今的大多数企业堆栈中,数据库是我们存储所有秘密的地方。它是安全屋,是待命室,也是用于存储可能非常私密或极具价值的物品的集散地。对于依赖它的数据库管理员、程序员和DevOps团队来说,保护它免受所
是否可以创建像图片上那样的边框?只需使用 css 边框属性。最终结果将是没 Angular 盒子。我不想添加额外的 html 元素。我只想为每个 li 元素添加 css 边框信息。 假设这是一个 ul
我是一名优秀的程序员,十分优秀!