Swift协议扩展方法用超类和子类调度

Ken*_* Ko 8 protocols ios swift protocol-extension

我发现了一个有趣的行为,似乎是一个bug ...

基于以下文章描述的行为:

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
Run Code Online (Sandbox Code Playgroud)

你知道这是一个bug还是设计?一位同事建议可能混合继承和协议扩展可能无法按预期工作.我打算使用协议扩展来提供默认实现......如果我不能这样做,那么我很遗憾地必须标记它@objc并返回到可选协议.

iam*_*ish 2

从帖子“Swift Bugs Future 的幽灵”中,以下是帖子末尾提到的协议扩展的调度规则。

\n\n
    \n
  1. 如果变量的推断类型是协议:
  2. \n
  3. 并且该方法是在原始协议中定义的,然后调用\n运行时类型\xe2\x80\x99s 实现,无论扩展中是否\n有默认实现。
  4. \n
  5. 并且原始协议中未定义该方法,然后调用默认实现。
  6. \n
  7. ELSE IF 推断的变量类型是 type THEN 则调用 type\xe2\x80\x99s 实现。
  8. \n
\n\n

因此,在您的情况下,您是说 method1() 是在协议中定义的,并且已在子类中实现。但是您的超类正在采用该协议,但它没有实现 method1() ,并且子类只是从超类继承,并且不直接采用该协议。这就是为什么我相信这就是当您调用 foo.method1() 时,它不会调用第 1 点和第 2 点所述的子类实现的原因。

\n\n

但当你这样做时,

\n\n
class SomeSuperclass: TheProtocol {\nfunc method1(){\n print("super class implementation of method1()")}\n}\n\nclass MyClass : SomeSuperclass {\n\noverride func method1() {\n    print("Called method1 from MyClass implementation")\n}\n\noverride func method2NotInProtocol() {\n    print("Called method2NotInProtocol from MyClass implementation")\n}\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后当你打电话时,

\n\n
 let foo: TheProtocol = MyClass()\nfoo.method1()  // Called method1 from MyClass implementation\nfoo.method2NotInProtocol() \n
Run Code Online (Sandbox Code Playgroud)\n\n

那么这个错误(这似乎是一个错误)的解决方法可能是,您需要在超类中实现协议方法,然后需要在子类中重写协议方法。华泰

\n