【发布时间】:2018-07-09 18:06:38
【问题描述】:
我正在努力将一些对我来说似乎很基本的东西建模。
让我们考虑一个虚构的服务/多播委托实现:
protocol Service { }
protocol Delegate { }
protocol Service1Delegate: Delegate {
func doSomething()
}
protocol Service1: Service {
func foo()
var delegates: [Service1Delegate] { get }
func register(delegate: Service1Delegate)
}
class MyService1: Service1 {
func foo() {
delegates.forEach { $0.doSomething() }
}
private(set) var delegates = [Service1Delegate]()
func register(delegate: Service1Delegate) {
self.delegates.append(delegate)
}
}
class A: Service1Delegate {
func doSomething() {
print("Hello A")
}
}
class B: Service1Delegate {
func doSomething() {
print("Hello B")
}
}
let service1 = MyService1()
service1.register(delegate: A())
service1.register(delegate: B())
service1.foo()
没问题,我打印了Hello A 和Hello B。
现在考虑第二个服务
protocol Service2Delegate: Delegate {
func doSomethingElse()
}
protocol Service2: Service {
func bar()
var delegates: [Service2Delegate] { get }
func register(delegate: Service2Delegate)
}
class MyService2: Service2 {
func bar() {
delegates.forEach { $0.doSomethingElse() }
}
private(set) var delegates = [Service2Delegate]()
func register(delegate: Service2Delegate) {
self.delegates.append(delegate)
}
}
Service1 和 Service2 都有一些与我希望通用的委托相关的代码。
所以我要引入一个新协议Delegable,如下所示:
protocol Delegable {
associatedtype D: Delegate
var delegates: [D] { get}
func register(delegate: D)
}
typealias DelegableService = Service & Delegable
我现在会定义这样的服务
protocol Service1: DelegableService {
func foo()
}
protocol Service2: DelegableService {
func bar()
}
但是,当实现它们并使用类型别名指定它们的委托类型时,编译器会抱怨我的实现不符合 Delegable
class MyService1: Service1 {
typealias D = Service1Delegate // <- the compiler does not like this, because it's not a concrete type
func foo() {
print("foo")
}
private(set) var delegates = [Service1Delegate]()
func register(delegate: Service1Delegate) {
self.delegates.append(delegate)
}
}
似乎我们只能使用具体类型而不是协议来键入别名。但具体类型暂时未知,性质不同(A类和B类),但都符合Service1Delegate。
在 Swift 中是否有解决方案?
【问题讨论】:
-
我认为这是关联类型的重点。协议可以使用关联类型来保持通用,然后任何符合该协议的具体类型都可以定义自己的类型别名以用于通用函数。也许类型约束是您正在寻找的?不确定您到底想要做什么。
-
我无法在 Xcode 10 (Swift 4.2) 中重现这一点。您的代码似乎工作正常。这可能已经修复了。
-
@Augie 我想做的是描述:使服务通用并符合协议,其关联类型是另一个协议。我想这是不能用swift表达的东西
-
@RobNapier 我无法使用 Xcode 10 / swift 4.2 编译它:/
-
啊,是的,我现在已经复制了。从协议继承的协议不符合该协议(就像协议不符合自身一样)。答案是减少您对协议的使用。如果您已经有两个类(A 和 B),请将它们设为单个抽象类的子类。或者创建一个类型橡皮擦。 robnapier.net/erasure 但是您正在推动协议超出他们的能力范围。具有关联类型的协议在 Swift 中非常棘手,除非您绝对需要它们,否则不应使用它们。它们有很多限制。
标签: ios swift swift-protocols type-alias associated-types