Swift - 如何覆盖具体子类中的扩展方法
Swift - How can I override an extension method in a concrete subclass
我在 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
}
我想你忘了覆盖子类中的超类 属性:
class Subclass : UIView {
var _property : Int = 1
override var property : Int {
get { return _property}
set(val) {_property = val}
}
}
看起来您可以为第二个超级 class 属性 覆盖 属性。例如,您可以通过对要覆盖 UIView
的 frame
属性 的 UILabel
进行扩展来访问 UIView
属性。此示例适用于 Xcode 6.3.2
extension UILabel {
override public var frame: CGRect {
didSet {
println("\(frame)")
}
}
}
与 一样,Swift 还不允许您覆盖 class 扩展中声明的方法。然而,我不确定你是否会得到你想要的行为,甚至 if/when Swift 有一天允许你覆盖这些方法。
考虑 Swift 如何处理协议和协议扩展。给定打印一些元语法变量名称的协议:
protocol Metasyntactic {
func foo() -> String
func bar() -> String
}
提供默认实现的扩展:
extension Metasyntactic {
func foo() -> String {
return "foo"
}
func bar() -> String {
return "bar"
}
}
和一个符合协议的class:
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 中覆盖我们的新方法:
class FooBarBaz : Metasyntactic {
func foo() -> String {
return "FOO"
}
func bar() -> String {
return "BAR"
}
func baz() -> String {
return "BAZ"
}
}
Swift 现在将使用 static dispatch 根据编译器推断的类型调用 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 仅对原始协议中声明的方法使用动态调度,不 方法在协议扩展中声明。我想 class 扩展也是如此。
我知道这个问题已经有人问过了。但这对于寻找更简单方法的人来说会很方便。有一种方法可以覆盖扩展方法。我知道它有点老套,但它做得很漂亮。
如果您使用 @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")
}
}
你不能通过正常方式做到这一点。
在 Apple 的文档中,您不能覆盖子类扩展中的方法。
此外,扩展可以为类型添加新功能,但不能覆盖现有功能。
https://docs.swift.org/swift-book/LanguageGuide/Extensions.html
Swift 5
class Class
{
@objc dynamic func make() { print("make from class") }
}
class SubClass: Class {}
extension SubClass {
override func make() {
print("override")
}
}
我在 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
}
我想你忘了覆盖子类中的超类 属性:
class Subclass : UIView {
var _property : Int = 1
override var property : Int {
get { return _property}
set(val) {_property = val}
}
}
看起来您可以为第二个超级 class 属性 覆盖 属性。例如,您可以通过对要覆盖 UIView
的 frame
属性 的 UILabel
进行扩展来访问 UIView
属性。此示例适用于 Xcode 6.3.2
extension UILabel {
override public var frame: CGRect {
didSet {
println("\(frame)")
}
}
}
与
考虑 Swift 如何处理协议和协议扩展。给定打印一些元语法变量名称的协议:
protocol Metasyntactic {
func foo() -> String
func bar() -> String
}
提供默认实现的扩展:
extension Metasyntactic {
func foo() -> String {
return "foo"
}
func bar() -> String {
return "bar"
}
}
和一个符合协议的class:
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 中覆盖我们的新方法:
class FooBarBaz : Metasyntactic {
func foo() -> String {
return "FOO"
}
func bar() -> String {
return "BAR"
}
func baz() -> String {
return "BAZ"
}
}
Swift 现在将使用 static dispatch 根据编译器推断的类型调用 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 仅对原始协议中声明的方法使用动态调度,不 方法在协议扩展中声明。我想 class 扩展也是如此。
我知道这个问题已经有人问过了。但这对于寻找更简单方法的人来说会很方便。有一种方法可以覆盖扩展方法。我知道它有点老套,但它做得很漂亮。
如果您使用 @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")
}
}
你不能通过正常方式做到这一点。
在 Apple 的文档中,您不能覆盖子类扩展中的方法。
此外,扩展可以为类型添加新功能,但不能覆盖现有功能。
https://docs.swift.org/swift-book/LanguageGuide/Extensions.html
Swift 5
class Class
{
@objc dynamic func make() { print("make from class") }
}
class SubClass: Class {}
extension SubClass {
override func make() {
print("override")
}
}