Swift - 如何在具体子类中覆盖扩展方法

Avn*_*arr 16 access-control ios swift swift-extensions

我有一个UIView实现协议的扩展

protocol SomeProtocol {
  var property : Int
}
    extension UIView : SomeProtocol {
      var property : Int {
        get {
          return 0
        }
        set {
          // do nothing
        }
      }
    }
Run Code Online (Sandbox Code Playgroud)

在具体的子类中,我想覆盖此扩展方法:

class Subclass : UIView, SomeProtocol {
  var _property : Int = 1
  var property : Int {
    get { return _property}
    set(val) {_property = val}
  }
}
Run Code Online (Sandbox Code Playgroud)

我设置断点并看到调用扩展方法而不是具体的子类方法:

var subclassObject = Subclass()

someObject.doSomethingWithConcreteSubclassObject(subclassObject)

// other code;

fun doSomethingWithConcreteSuclassObject(object : UIView) {
  var value = object.property // always goes to extension class get/set
}
Run Code Online (Sandbox Code Playgroud)

Chr*_*ick 15

正如其他人所说,Swift(还)不允许您覆盖类扩展中声明的方法.但是,我不确定你是否会得到你想要的行为,即使/当Swift有一天允许你覆盖这些方法.

考虑Swift如何处理协议和协议扩展.给定一个打印一些metasyntactic变量名称的协议:

protocol Metasyntactic {
    func foo() -> String
    func bar() -> String
}
Run Code Online (Sandbox Code Playgroud)

提供默认实现的扩展:

extension Metasyntactic {
    func foo() -> String {
        return "foo"
    }

    func bar() -> String {
        return "bar"
    }
}
Run Code Online (Sandbox Code Playgroud)

还有一个符合协议的类:

class FooBar : Metasyntactic {
    func foo() -> String {
        return "FOO"
    }

    func bar() -> String {
        return "BAR"
    }
}
Run Code Online (Sandbox Code Playgroud)

斯威夫特将使用动态分配调用适当的实现foo()bar()基于每个变量的运行时类型,而不是由编译器推断类型:

let a = FooBar()
a.foo()  // Prints "FOO"
a.bar()  // Prints "BAR"

let b: Metasyntactic = FooBar()
b.foo()  // Prints "FOO"
b.bar()  // Prints "BAR"
Run Code Online (Sandbox Code Playgroud)

但是,如果我们进一步扩展协议以添加新方法:

extension Metasyntactic {
    func baz() -> String {
        return "baz"
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我们在符合协议的类中覆盖我们的新方法:

class FooBarBaz : Metasyntactic {
    func foo() -> String {
        return "FOO"
    }

    func bar() -> String {
        return "BAR"
    }

    func baz() -> String {
        return "BAZ"
    }
}
Run Code Online (Sandbox Code Playgroud)

Swift现在将使用静态调度baz()根据编译器推断的类型调用相应的实现:

let a = FooBarBaz()
a.baz()  // Prints "BAZ"

let b: Metasyntactic = FooBarBaz()
b.baz()  // Prints "baz"
Run Code Online (Sandbox Code Playgroud)

Alexandros Salazar有一篇很棒的博客文章,深入解释了这种行为,但只要说Swift只对原始协议中声明的方法使用动态调度,而不是协议扩展中声明的方法.我想同样的类扩展也是如此.