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

时间:2015-04-27 10:24:50

标签: ios swift access-control swift-extensions

我对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
}

6 个答案:

答案 0 :(得分:14)

作为others have noted,Swift(还)不允许您覆盖类扩展中声明的方法。但是,我不确定你是否会得到你想要的行为,即使/当Swift有一天允许你覆盖这些方法时。

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

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有a fantastic blog post explaining this behavior in depth,但可以说Swift只对原始协议中声明的方法使用动态分派,对于协议扩展中声明的方法,。我想同样的类扩展也是如此。

答案 1 :(得分:0)

看起来你可以覆盖第二超级属性的属性。例如,您可以通过对想要覆盖UIView UILabel属性的frame进行扩展来访问UIView属性。此示例适用于Xcode 6.3.2

extension UILabel {

     override public var frame: CGRect {

         didSet {
             println("\(frame)")
        }
     }
}

答案 2 :(得分:0)

我知道这个问题已经被问过了。但对于那些寻求更简单方法的人来说,这将非常方便。有一种覆盖扩展方法的方法。我知道它有点hacky但它​​完美地完成了这项工作。

如果您使用@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")
      }  
  }

答案 3 :(得分:0)

您无法通过常规方式进行此操作。

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

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

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

答案 4 :(得分:0)

斯威夫特 5

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

class SubClass: Class {}

extension SubClass {
    override func make() {
        print("override")
    }
}

答案 5 :(得分:-3)

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

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