假设情景:
有课程:ClassA
;和ClassB
。两者都实现ProtocolC
,其中包含单个要求func createKey()
。 ProtocolC
有一个extension
来实现createKey()
,因为就此功能而言,ClassA
和ClassB
所需的功能是相同的。但是,createKey()
的实现需要访问uniqueKey
和ClassA
都包含的名为ClassB
的私有变量,其值必须在两个类中不同(你可能想象的那样)。 extension
中createKey()
的{{1}}因此变得无用 - 因为变量是ProtocolC
- 意味着其代码必须在fileprivate
和{{1}中重复}}。但重复的代码是禁止编程的。解决方案可以使用超类而不是协议扩展,但这会削弱Swift试图实现的目标。继承是斯威夫特禁忌。
ClassA
ClassB
需要锁定在两个类中,不能设置,也不能从没有。 Swift编写的解决方案是什么:可以访问私有属性的通用代码;同时避免继承?
感谢您的阅读。
答案 0 :(得分:2)
这里的东西非常接近你的理想。缺点是扩展方法中运行的运行时协议,但它实现了您正在寻找的访问控制级别(fileprivate
存储var)和通过协议扩展重用代码:
fileprivate protocol UniqueKeyDefining {
var uniqueKey: String? { get set }
}
class ClassA: ProtocolC, UniqueKeyDefining {
fileprivate var uniqueKey: String?
}
class ClassB: ProtocolC, UniqueKeyDefining {
fileprivate var uniqueKey: String?
}
protocol ProtocolC {
func createKey()
}
extension ProtocolC {
func createKey(){
if var hasUniqueKey = self as? UniqueKeyDefining {
hasUniqueKey.uniqueKey = NSUUID().uuidString
} else {
// Some default behavior if the conformer to ProtocolC isn't also UniqueKeyDefining
}
}
}
协议UniqueKeyDefining
在使用ClassA
和ClassB
声明的文件之外是不可见的,因此文件外的任何代码都不知道这些类符合它或者可以看到他们的uniqueKey
ivars。
ProtocolC
的特定协议扩展名在同一个文件中声明,因此 知道UniqueKeyDefining
并且可以有条件地将self
强制转换为该协议运行时通过该fileprivate协议访问uniqueKey
ivar。
对于此文件之外的类,它似乎不具有可伸缩性或可重用性,但它符合我从您的问题中解释的一系列狭窄的要求。
答案 1 :(得分:1)
您正在尝试访问协议中未定义的内容。扩展应该仅基于其公共细节。你不应该访问他们的私人。
我认为你真正想要的是"分享实施"而不是与访问控制和类型系统斗争。如果您需要共享实现,只需进行显式实现并共享它们。
protocol ProtocolC {
func createKey()
}
class ClassA: ProtocolC {
private var impl = Impl()
func createKey() {
impl.createKey()
}
}
class ClassB: ProtocolC {
private var impl = Impl()
func createKey() {
impl.createKey()
}
}
private struct Impl {
private(set) var uniqueKey: String?
mutating func createKey(){
// Lock here.
uniqueKey = NSUUID().uuidString
// Unlock here.
}
}
避免对私有细节的依赖是extension
的意图和设计目标之一,因为这种依赖会使代码变得脆弱,而这种脆弱性是子类化的主要问题之一。