19

我在 UIView 上有一个扩展,实现了一个协议

protocol SomeProtocol {
  var property : Int
}
    extension UIView : SomeProtocol {
      var property : Int {
        get {
          return 0
        }
        set {
          // do nothing
        }
      }
    }

在一个具体的子类中,我想重写这个扩展方法:

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

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

var subclassObject = Subclass()

someObject.doSomethingWithConcreteSubclassObject(subclassObject)

// other code;

fun doSomethingWithConcreteSuclassObject(object : UIView) {
  var value = object.property // always goes to extension class get/set
}
4

6 回答 6

17

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

考虑一下 Swift 如何处理协议和协议扩展。给定一个打印一些元语法变量名称的协议:

protocol Metasyntactic {
    func foo() -> String
    func bar() -> String
}

提供默认实现的扩展:

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

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

还有一个符合协议的类:

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

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

Swift 将使用动态调度来调用适当的实现,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"

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

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

如果我们在一个符合协议的类中重写我们的新方法:

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

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

    func baz() -> String {
        return "BAZ"
    }
}

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

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

let b: Metasyntactic = FooBarBaz()
b.baz()  // Prints "baz"

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

于 2016-10-09T06:31:41.857 回答
3

我知道这个问题已经被问过一段时间了。但这对于寻找更简单方法的人来说会很方便。有一种方法可以覆盖扩展方法。我知道它有点老套,但它做得很好。

如果您声明您的协议@objc

@objc protocol MethodOverridable {
   func overrideMe()
}

在扩展中

extension MainClass: MethodOverridable {
     func overrideMe() {
        print("Something useful")
     } 
}

子类- 您可以在子类中覆盖它。它就像魔术一样工作。好吧,在添加@objc它时并不是真的暴露了你的protocol to Objective-C和它的Runtime. 这允许您的子类覆盖。

 class SubClass: MainClass {
     override func overrideMe() {
          print("Something more useful")
      }  
  }
于 2018-02-23T14:59:33.927 回答
1

斯威夫特 5

class Class
{
    @objc dynamic func make() { print("make from class") }
}

class SubClass: Class {}

extension SubClass {
    override func make() {
        print("override")
    }
}
于 2021-08-09T18:28:24.617 回答
0

It looks like you can override property for 2nd super class property. For example, you can access UIView property by making extension to the UILabel wanting to override frame property of UIView. This sample works for me in Xcode 6.3.2

extension UILabel {

     override public var frame: CGRect {

         didSet {
             println("\(frame)")
        }
     }
}
于 2015-07-23T07:57:12.263 回答
0

你不能通过正常的方式做到这一点。

在 Apple 的文档中,您不能在子类的扩展中覆盖方法。

此外,扩展可以为类型添加新功能,但不能覆盖现有功能。

https://docs.swift.org/swift-book/LanguageGuide/Extensions.html

于 2020-11-27T17:26:41.697 回答
-3

我认为您忘记覆盖子类中的超类属性:

class Subclass : UIView {
    var _property : Int = 1
    override var property : Int {
        get { return _property}
        set(val) {_property = val}
    }
}
于 2015-04-27T10:28:43.583 回答