I'm trying to implement an extended function that should differ based on what type of class is using it. The objects need to be UIView (or subclass). It should always use function extended on the specified type, but if it doesn't conform to any of them they should use the UIView method instead (as a fallback).
Here is an example of what I'm trying to do:
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")
}
}
Excecute:
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"
Which now prints:
Im an UIView
Im an UIView
Im an UIView
Im an UIView
This means that it always uses the UIView method, even though I want it to use it's own methods. My goal is so it prints:
Im an UIView
Im an UIView
im an UILabel
im an UIImageView
If a protocol defines a method, and provides a default implementation in an extension, a class can override that method, and the override will be called for any reference to the instance, even if the reference's type is declared as the protocol.
Swift version: 5.6. The override is used when you want to write your own method to replace an existing one in a parent class. It's used commonly when you're working with UIViewControllers , because view controllers already come with lots of methods like viewDidLoad() and viewWillAppear() .
You can achieve that as below, You just need to expose aProtocol
to Objective-c
runtime for overriding
its methods in the 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")
}
}
Output:
Im an UIView
Im an UIView
im an UILabel
im an UIImageView
concrete type conforming to a protocol will used over the protocol constraint. So by changing this:
extension UIView: aProtocol {
func doSomething(completion: (Bool) -> ()) {
print("Im an UIView")
}
}
to this:
extension aProtocol where Self: UIView {
func doSomething(completion: (Bool) -> ()) {
print("im an UIView")
}
}
extension UIView: aProtocol {}
Your code will work as you expect.
You can achieve all of your desired prints with this:
extension aProtocol {
func doSomething(completion: completionBlock) {
print("im a \(type(of: self))")
}
}
extension UIView: aProtocol {}
This means you can check the actual type of the object right inside the protocol extension.
Protocol extensions doesn't override any method. In fact, they are just default implementation if the actual concrete type doesn't implement it.
And protocol constraint defines witch type can infer it's default implementation. So:
extension aProtocol where Self: UILabel
means any subcalss of UILabel
that is conformed to aProtocol
and does not implement the requirements should infer de default implementation. So this will work only if UILabel
conforms to aProtocol
directly:
extension UILabel: aProtocol {}
or if it's supercalss conforms to it:
extension UIView: aProtocol {}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With