当您遇到这样的问题时,您想知道 Swift 语言本身的局限性,这有助于将问题简化为更简单的版本。
首先,让我们问:是否可以扩展采用协议的协议,作为将该协议要求的默认实现注入到最终采用的类中的一种方式?是的;这段代码是合法的:
protocol Speaker {
func speak()
}
protocol DefaultSpeaker : Speaker {
}
extension DefaultSpeaker {
func speak() {
print("howdy")
}
}
class Adopter : DefaultSpeaker {
}
好吧,那么你的代码还做了什么?好吧,它还注入了一个额外的要求(实例变量)。那合法吗?是的。这段代码也是合法的:
protocol Speaker {
func speak()
}
protocol DefaultSpeaker : Speaker {
var whatToSay : String {get}
}
extension DefaultSpeaker {
func speak() {
print(self.whatToSay)
}
}
class Adopter : DefaultSpeaker {
var whatToSay = "howdy"
}
那么 Swift 不喜欢什么?还有哪些是我们在这里没有做而您的代码却做了的事情?事实上,原始协议是@objc
。如果我们改变protocol Speaker
to @objc protocol Speaker
(并进行所有其他必要的更改),代码停止编译:
@objc protocol Speaker {
func speak()
}
@objc protocol DefaultSpeaker : Speaker {
var whatToSay : String {get}
}
extension DefaultSpeaker {
func speak() {
print(self.whatToSay)
}
}
class Adopter : NSObject, DefaultSpeaker { // ERROR
var whatToSay = "howdy"
}
我猜测这是因为 Objective-C 对协议扩展一无所知。由于我们对所需协议方法的实现取决于协议扩展,因此我们无法以一种使编译器满意的方式采用协议,即从 Objective-C 的角度来看已经满足了要求。我们必须在类中实现需求,Objective-C 可以在类中看到我们的实现(这正是您的解决方案所做的):
@objc protocol Speaker {
func speak()
}
@objc protocol DefaultSpeaker : Speaker {
var whatToSay : String {get}
}
extension DefaultSpeaker {
func speak2() {
print(self.whatToSay)
}
}
class Adopter : NSObject, DefaultSpeaker {
var whatToSay = "howdy"
func speak() {
self.speak2()
}
}
因此,我的结论是,您的解决方案已经是最好的了。
您所做的实际上更像是这样,我们在采用者类上使用扩展来注入“钩子”方法:
@objc protocol Speaker {
func speak()
}
@objc protocol DefaultSpeaker : Speaker {
var whatToSay : String {get}
}
extension DefaultSpeaker {
func speak2() {
print(self.whatToSay)
}
}
class Adopter : NSObject {
}
extension Adopter : DefaultSpeaker {
var whatToSay : String { return "howdy" }
func speak() {
self.speak2()
}
}
这有效,因为最后extension
是 Objective-C 的东西can请参阅:Objective-C 类的扩展实际上是 Objective-C 可以理解的类别。