我有一个关于 swift 中单例的简单问题,经过大量研究后我没有找到明确的答案。所以问题是 - 我有一个 StructA
:
struct StructA {
static let shared = StructA()
private init() {}
public func someFuncA() {
//self.somefuncB()
//or
//StructA.shared.someFuncB()
}
private func someFuncB() {
}
}
我像这样从其他类调用 someFuncA
StructA.shared.someFuncA()
:
你能解释一下
self.somefuncB()
和StructA.shared.someFuncB()
有什么区别吗(见上面的代码)? 在我看来没有区别,但是如果我有这样的代码时self.somefuncB()
必须在回调中调用 -那么我必须使用
[weak self]
吗?public func someFuncA() { someFuncWithCallback() { [weak self] in self?.somefuncB() } }
或者我可以直接写
public func someFuncA() { someFuncWithCallback() { StructA.shared.someFuncB() } }
我用“Leaks”(Xcode 工具)检查了这段代码,它说没有泄漏,因为我知道 closer/block 拥有其中使用的对象,所以有人可以解释一下这里发生了什么吗?谢谢。
最佳答案
几个想法:
struct
单例在术语上是自相矛盾的。单例是一个应该只有一个实例的对象。但是struct
是一个值类型并且具有“复制”内存语义。考虑:var a = StructA.shared ...
a
是所谓的单例的副本,而不是对它的引用。为了避免这个问题,单例应该是一个类
,一个引用类型。我同意 Paulw11 的观点,
self
是一种更简单、更常用的方法。不过,我还建议,通过引用self
,您可以更好地编写 (a) 不依赖于单例类的代码; (b) 开启该类在未来某个日期被子类化的可能性。考虑到我建议使用
self
模式,因此我也建议避免明显的潜在强引用循环(例如通过使用weak
或unowned
在需要的地方引用)。仅仅因为它恰好是单例就故意创建强引用循环是没有意义的。如果您曾经重新考虑使用单例模式的决定,为什么要编写您知道必须重写的代码,尤其是当您一开始就知道避免强引用是多么容易时?仅供引用,我看到的行为与您报告的行为相同,即如果
static
参与理论上的强引用循环,则不会将其识别为此类。但是,如果您将static
属性设置为nil
(假设它是可变的和可选的),则会出现强引用。这一观察并没有改变我上面的建议,即避免你所知道的在任何其他情况下都是强引用循环。我只是在证实你的经验观察。
关于上面的第 2 点到第 4 点(我考虑将单例模式最终重构为其他模式),我应该说这不是纯粹的学术观察。有一些单例类型并不少见,后来,随着项目变得更加复杂或使用更多的单元测试,重新审视该决定并开始使用依赖注入(inject)或其他模式。如果您还必须编辑所有单个函数,那将是一种耻辱。如果您编写的代码不依赖于对象的单例性质,您最终会得到更健壮的代码库,同时减少不必要的内部依赖。
关于swift - 在单例结构中使用 self,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47906064/