如何覆盖子类的 swift 协议函数(例如 UIView 的 UILabel)
How to override swift protocol functions for subclasses (e.g. UILabel from UIView)
我正在尝试实现一个扩展功能,该功能应该根据 class 使用它的类型而有所不同。
对象需要是 UIView(或 subclass)。它应该始终使用在指定类型上扩展的函数,但如果它不符合其中任何一个,则应改用 UIView 方法(作为后备)。
这是我正在尝试做的一个例子:
protocol aProtocol {
typealias completionBlock = (_ finished:Bool)->()
func doSomething(completion: completionBlock)
}
extension UIView: aProtocol {
func doSomething(completion: (Bool) -> ()) {
print("Im an UIView")
}
}
extension aProtocol where Self: UILabel {
func doSomething(completion: (Bool) -> ()) {
print("im an UILabel")
}
}
extension aProtocol where Self: UIImageView {
func doSomething(completion: (Bool) -> ()) {
print("im an UIImageView")
}
}
执行:
UIView().doSomething { (foo) in } // Should print "Im an UIView"
UIButton().doSomething { (foo) in } // Should print "Im an UIView" (UIButton doesent have specified extended function so should fall back on the UIView function)
UILabel().doSomething { (foo) in } // Should print "im an UILabel"
UIImageView().doSomething { (foo) in } // Should print "im an UIImageView"
现在打印:
Im an UIView
Im an UIView
Im an UIView
Im an UIView
这意味着它总是使用 UIView 方法,即使我希望它使用它自己的方法。我的目标是打印:
Im an UIView
Im an UIView
im an UILabel
im an UIImageView
protocol aProtocol {
typealias completionBlock = (_ finished:Bool)->()
}
extension aProtocol {
func doSomething(completion: completionBlock) {
switch self {
case is UILabel:
print("im a label")
break
case is UIView:
print("im a view")
break
default:
break
}
}
}
extension UIView: aProtocol{}
extension UILabel: aProtocol{}
func testing() {
let view = UIView()
view.doSomething { (value) in
// Do something
}
let label = UILabel()
label.doSomething { (value) in
// Do something
}
}
确保 UIView 的大小写位于列表的底部(或至少在您要屏蔽的所有内容下方)
- 答案
符合协议的具体类型将用于协议约束。所以通过改变这个:
extension UIView: aProtocol {
func doSomething(completion: (Bool) -> ()) {
print("Im an UIView")
}
}
对此:
extension aProtocol where Self: UIView {
func doSomething(completion: (Bool) -> ()) {
print("im an UIView")
}
}
extension UIView: aProtocol {}
您的代码将按预期运行。
- 备选方案
您可以通过以下方式实现所有想要的打印效果:
extension aProtocol {
func doSomething(completion: completionBlock) {
print("im a \(type(of: self))")
}
}
extension UIView: aProtocol {}
这意味着您可以在协议扩展中检查对象的实际类型。
- 解释
协议扩展不会覆盖任何方法。事实上,如果实际的具体类型没有实现它们,它们只是默认实现。
和协议约束定义了类型可以推断它的默认实现。所以:
extension aProtocol where Self: UILabel
表示 UILabel
的任何符合 aProtocol
且未实现要求的子类应推断默认实现。所以这只有在 UILabel
直接符合 aProtocol
的情况下才有效:
extension UILabel: aProtocol {}
或者如果它的 supercalss 符合它:
extension UIView: aProtocol {}
您可以如下实现,您只需要将 aProtocol
暴露给 Objective-c
运行时,以便 overriding
它在 extension
.
中的方法
@objc protocol aProtocol {
typealias completionBlock = (_ finished:Bool)->()
func doSomething(completion: completionBlock)
}
extension UIView: aProtocol {
func doSomething(completion: (Bool) -> ()) {
print("Im an UIView")
}
}
extension UILabel {
override func doSomething(completion: (Bool) -> ()) {
// you can call super.doSomething(completion: completion)
print("im an UILabel")
}
}
extension UIImageView {
override func doSomething(completion: (Bool) -> ()) {
// you can call super.doSomething(completion: completion)
print("im an UIImageView")
}
}
输出:
Im an UIView
Im an UIView
im an UILabel
im an UIImageView
我正在尝试实现一个扩展功能,该功能应该根据 class 使用它的类型而有所不同。 对象需要是 UIView(或 subclass)。它应该始终使用在指定类型上扩展的函数,但如果它不符合其中任何一个,则应改用 UIView 方法(作为后备)。
这是我正在尝试做的一个例子:
protocol aProtocol {
typealias completionBlock = (_ finished:Bool)->()
func doSomething(completion: completionBlock)
}
extension UIView: aProtocol {
func doSomething(completion: (Bool) -> ()) {
print("Im an UIView")
}
}
extension aProtocol where Self: UILabel {
func doSomething(completion: (Bool) -> ()) {
print("im an UILabel")
}
}
extension aProtocol where Self: UIImageView {
func doSomething(completion: (Bool) -> ()) {
print("im an UIImageView")
}
}
执行:
UIView().doSomething { (foo) in } // Should print "Im an UIView"
UIButton().doSomething { (foo) in } // Should print "Im an UIView" (UIButton doesent have specified extended function so should fall back on the UIView function)
UILabel().doSomething { (foo) in } // Should print "im an UILabel"
UIImageView().doSomething { (foo) in } // Should print "im an UIImageView"
现在打印:
Im an UIView
Im an UIView
Im an UIView
Im an UIView
这意味着它总是使用 UIView 方法,即使我希望它使用它自己的方法。我的目标是打印:
Im an UIView
Im an UIView
im an UILabel
im an UIImageView
protocol aProtocol {
typealias completionBlock = (_ finished:Bool)->()
}
extension aProtocol {
func doSomething(completion: completionBlock) {
switch self {
case is UILabel:
print("im a label")
break
case is UIView:
print("im a view")
break
default:
break
}
}
}
extension UIView: aProtocol{}
extension UILabel: aProtocol{}
func testing() {
let view = UIView()
view.doSomething { (value) in
// Do something
}
let label = UILabel()
label.doSomething { (value) in
// Do something
}
}
确保 UIView 的大小写位于列表的底部(或至少在您要屏蔽的所有内容下方)
- 答案
符合协议的具体类型将用于协议约束。所以通过改变这个:
extension UIView: aProtocol {
func doSomething(completion: (Bool) -> ()) {
print("Im an UIView")
}
}
对此:
extension aProtocol where Self: UIView {
func doSomething(completion: (Bool) -> ()) {
print("im an UIView")
}
}
extension UIView: aProtocol {}
您的代码将按预期运行。
- 备选方案
您可以通过以下方式实现所有想要的打印效果:
extension aProtocol {
func doSomething(completion: completionBlock) {
print("im a \(type(of: self))")
}
}
extension UIView: aProtocol {}
这意味着您可以在协议扩展中检查对象的实际类型。
- 解释
协议扩展不会覆盖任何方法。事实上,如果实际的具体类型没有实现它们,它们只是默认实现。
和协议约束定义了类型可以推断它的默认实现。所以:
extension aProtocol where Self: UILabel
表示 UILabel
的任何符合 aProtocol
且未实现要求的子类应推断默认实现。所以这只有在 UILabel
直接符合 aProtocol
的情况下才有效:
extension UILabel: aProtocol {}
或者如果它的 supercalss 符合它:
extension UIView: aProtocol {}
您可以如下实现,您只需要将 aProtocol
暴露给 Objective-c
运行时,以便 overriding
它在 extension
.
@objc protocol aProtocol {
typealias completionBlock = (_ finished:Bool)->()
func doSomething(completion: completionBlock)
}
extension UIView: aProtocol {
func doSomething(completion: (Bool) -> ()) {
print("Im an UIView")
}
}
extension UILabel {
override func doSomething(completion: (Bool) -> ()) {
// you can call super.doSomething(completion: completion)
print("im an UILabel")
}
}
extension UIImageView {
override func doSomething(completion: (Bool) -> ()) {
// you can call super.doSomething(completion: completion)
print("im an UIImageView")
}
}
输出:
Im an UIView
Im an UIView
im an UILabel
im an UIImageView