繁体   English   中英

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

[英]Swift protocol extension method dispatch with superclass and subclass

我发现了一个有趣的行为,似乎是一个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

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

从后面的Swift Bugs Future的Ghost ,这里是在帖子末尾提到的协议扩展的调度规则。

  1. 如果变量的推断类型是协议:
  2. 并且该方法在原始协议中定义,然后调用运行时类型的实现,而不管扩展中是否存在默认实现。
  3. 并且该方法未在原始协议中定义,然后调用默认实现。
  4. ELSE如果变量的推断类型是THEN类型,则调用类型的实现。

所以在你的情况下,你说method1()是在协议中定义的,它已经在子类中实现。 但是你的超类正在采用协议,但它没有实现method1(),而子类只是继承自Superclass而不直接采用协议。 这就是为什么我认为这是你调用foo.method1()的原因,它不会调用第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

请检查以下代码:

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)。 这按预期工作。

未考虑的选项是将协议拆分为几个较小的协议,这样超类不需要符合包含它不打算实现的方法的协议。 然后,子类可以单独订阅这些其他协议。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM