Search code examples
iosswiftswift-protocolsswift-extensions

Alternative to override extension's method


I want to extend UIView by adding some functions, and override them in any subclass of UIView that I want. I found in apple documentations that I can't override extensions (and the compiler will complain) which make some sense. So

I need someone to suggest an alternative way to the below:

extension UIView { 
  func hide() { //do almost nothing } 
}

class myLabel: UILabel { 
  override func hide() { 
    //do work on uilabel that can't be done on imgView
  }
}

class myImageView: UIImageView {
 override func hide() { 
    //do work on imgView that can't be done on uilabel
  }
}

And the reason I want this is that later in my code I will face the below code and I have to many subclasses and I don't want to write too many if-lets trying to cast the view to myLabel, myTextView, myImageView... etc

let view = cell.viewWithTag(someTag)
// and I want to write this below without casting
view.hide()

I tried with protocols and protocol extensions but I couldn't make it though.

Any thoughts?


Note: func hide() is just an example. My func will have more to do.
**Question updated to be clear.


Solution

  • EDIT: Updating answer to make use of protocols also

    Protocols does in various ways enable to you replace subclassing in some cases however you still need your class to conform to the protocol to be able to see and override those methods

    You can have a protocol for example:

    protocol SomeProtocol {
        func hide()
    }
    

    To do what you are intending to do it is best to have a parent subclass UIView with all functions that can be overridden for example (in this updated answer you can have your methods to override inside the protocol and have your subclasses conform to it):

    class ParentView : UIView, SomeProtocol {
        func hide() {
            print("PARENT")
        }
    
        func anyOtherMethod() {
    
        }
    }
    

    and then have all the other UIView's that need to override those methods subclass ParentView:

    class ViewOne : ParentView {
        override func hide() {
            print("VIEW ONE")
        }
    }
    
    class ViewTwo : ParentView {
        override func hide() {
            print("VIEW TWO")
        }
    }
    

    So even if you later place this code:

    let view = cell.viewWithTag(someTag)
    // and I want to write this below without casting
    view.hide()
    

    you won't need to explicitly cast your UIView's, the view will call it's intended overridden method, unless and until you call super in your overridden method also

    EDIT: More on making use of protocols

    In the case you need other controls to also have a hide() method to override then you can still have to subclass, for example in the case of UILabel you need to override it:

    class ParentLabel : UILabel, SomeProtocol {
        func hide() {
            print("PARENT LABEL")
        }
    }
    

    then you can write the intended code with casting to your protocol

    if let view = cell.viewWithTag(someTag) as? SomeProtocol {
        view.hide() // prints PARENT LABEL
    }
    

    and either use that subclassed UILabel control or if you need in some cases some label to override that behavior then you can still create a child subclass of ParentLabel:

    class LabelOne : ParentLabel {
        override func hide() {
            print("LABEL ONE")
        }
    }