我发现了一个有趣的行为,似乎是个错误...
基于以下文章描述的行为:
https://medium.com/ios-os-x-development/swift-protocol-extension-method-dispatch-6a6bf270ba94
http://nomothetis.svbtle.com/the-ghost-of-swift-bugs-future
当我添加SomeSuperclass
时,输出不是我所期望的,而不是直接采用协议。
protocol TheProtocol {
func method1()
}
extension TheProtocol {
func method1() {
print("Called method1 from protocol extension")
}
func method2NotInProtocol() {
print("Called method2NotInProtocol from protocol extension")
}
}
// This is the difference - adding a superclass
class SomeSuperclass: TheProtocol {
}
// It works as expected when it simply adopts TheProtocol, but not when it inherits from a class that adopts the protocol
class MyClass: SomeSuperclass {
func method1() {
print("Called method1 from MyClass implementation")
}
func method2NotInProtocol() {
print("Called method2NotInProtocol from MyClass implementation")
}
}
let foo: TheProtocol = MyClass()
foo.method1() // expect "Called method1 from MyClass implementation", got "Called method1 from protocol extension"
foo.method2NotInProtocol() // Called method2NotInProtocol from protocol extension
你知道这是一个bug还是设计?一位同事建议可能混合继承和协议扩展可能无法按预期工作。我打算使用协议扩展来提供默认实现......如果我不能这样做,那么我将不得不将其标记为@objc
并返回可选协议。
答案 0 :(得分:1)
从帖子The Ghost of Swift Bugs Future开始,以下是帖子末尾提到的协议扩展的调度规则。
所以在你的情况下,你说method1()是在协议中定义的,它已经在子类中实现了。但是你的超类正在采用协议,但它没有实现method1(),而子类只是继承自Superclass而不直接采用协议。这就是为什么我认为这是你调用foo.method1()的原因,它不会调用第1点和第1点所述的子类实现。 2。
但是当你这样做时,
class SomeSuperclass: TheProtocol {
func method1(){
print("super class implementation of method1()")}
}
class MyClass : SomeSuperclass {
override func method1() {
print("Called method1 from MyClass implementation")
}
override func method2NotInProtocol() {
print("Called method2NotInProtocol from MyClass implementation")
}
}
然后当你打电话时,
let foo: TheProtocol = MyClass()
foo.method1() // Called method1 from MyClass implementation
foo.method2NotInProtocol()
那么这个bug(似乎是一个bug)的解决方法是,你需要在超类中实现协议方法,然后你需要覆盖子类中的协议方法。 HTH
答案 1 :(得分:0)
请检查以下代码:
import UIKit
protocol TheProtocol {
func method1()
func method2NotInProtocol()
}
extension NSObject {
func method1() {
print("Called method1 from protocol extension")
}
func method2NotInProtocol() {
print("Called method2NotInProtocol from protocol extension")
}
}
// This is the difference - adding a superclass
class SomeSuperclass :NSObject, TheProtocol {
override func method1() {
print("Called method1 from SomeSuperclass implementation")
}
}
// It works as expected when it simply adopts TheProtocol, but not when it inherits from a class that adopts the protocol
class MyClass : SomeSuperclass {
override func method1() {
print("Called method1 from MyClass implementation")
}
override func method2NotInProtocol() {
print("Called method2NotInProtocol from MyClass implementation")
}
}
let foo: TheProtocol = MyClass()
foo.method1() // expect "Called method1 from MyClass implementation", got "Called method1 from protocol extension"
foo.method2NotInProtocol() // Called method2NotInProtocol from protocol extension
不是将扩展写入TheProtocol,而是将扩展写入抽象类(上面代码中的NSObject)。这可以按预期工作。
答案 2 :(得分:0)
一个尚未考虑的选项是将您的协议分成几个较小的协议,这样,超类不需要符合包含其不打算实现的方法的协议。然后,子类可以分别订阅其他协议。