覆盖扩展方法的替代方法

5
我希望通过添加一些函数来扩展UIView,并在任何我想要的UIView子类中覆盖它们。我在苹果文档中发现,我不能覆盖扩展(编译器会抱怨),这有一定道理。因此,
我需要有人建议下面的替代方法:
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
  }
}

我希望这样做的原因是,后面在我的代码中会遇到以下的代码,而我有太多的子类,不想写太多的if-lets试图将view转换为myLabel、myTextView、myImageView等

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

我尝试使用协议协议扩展,但我无法成功。

你有什么想法吗?


注意:func hide()只是一个示例。我的函数将有更多操作。
**问题已更新以更清晰表达。


2
创建一个UIView的子类,然后再让你的UIView子类成为另一个类的子类。如果你需要不同的行为,那么扩展并不是正确的方法。 - Paulw11
我需要在多个位置实现 hide() 函数。我有 myLabel: UILabel {}myImgView: UIImageView {} 等等,所以我无法子类化 UIView,因为如果我把 myLabel: myView 这样做,那么我就无法将它子类化为 UILabel 了。 - Ahmed Fathi
你可以采用通用的实现方式,继承 UIView 类,或者需要对每个现有的 UIView 子类进行子类化或扩展。 - Paulw11
是的,但你考虑过“协议”吗? 当我看到一些像“Hashable”这样的协议时,我觉得我可以创建自己的协议来解决问题,但我还不知道怎么做。你认为“协议”能帮助吗? - Ahmed Fathi
你可以使用协议,但仍需要扩展每个相关的UIView子类以采用该协议并为该类提供实现。协议只是定义扩展需要实现的方法。您可以使用协议本身的扩展来提供默认实现,从而消除在默认实现足够的情况下编写特定代码的需要。 - Paulw11
1个回答

2

编辑:更新答案,使用协议进行替换子类化

协议在某些情况下可以帮助你替换子类化,但是你仍然需要使你的类符合协议才能看到和重写那些方法。

例如,你可以拥有一个协议:

protocol SomeProtocol {
    func hide()
}

为了达到你想要的效果,最好是创建一个父类为UIView的子类,并提供所有可重写的函数。例如(在这个更新后的答案中,你可以将要重写的方法放在协议内,并让你的子类遵循它):
class ParentView : UIView, SomeProtocol {
    func hide() {
        print("PARENT")
    }

    func anyOtherMethod() {

    }
}

然后,需要重写这些方法的其他所有UIView都应该是ParentView的子类:

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

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

因此,即使您稍后放置了此代码:

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

你不需要明确地转换你的UIView,视图将调用它的预期重写方法,除非你在你的重写方法中也调用了super

编辑:更多关于使用协议的信息

如果您需要其他控件也有一个hide()方法来覆盖,则仍然需要子类化,例如在UILabel的情况下,您需要覆盖它:

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

然后,您可以使用强制转换到您的协议来编写预期的代码。
if let view = cell.viewWithTag(someTag) as? SomeProtocol {
    view.hide() // prints PARENT LABEL
}

你可以创建一个子类继承UILabel,然后使用该子类的控件,如果需要在某些情况下覆盖标签行为,则仍然可以创建ParentLabel的子类:

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

谢谢你的帮助。我已经更新了问题中的示例,你会发现在这种情况下子类化并不是解决方案。 - Ahmed Fathi
是的,我在发布问题后看到了它。我知道你正在寻找协议作为答案,但那也不会起作用,你仍然需要子类化并将你的协议应用于你的子类视图,以便它可以看到要重写的协议内部的方法。 - Azhar Ali
我使用了您提供的协议,但是我无法编写这行代码 view.hide(),因为视图 UIView 仍需要遵循 SomeProtocol 协议。 - Ahmed Fathi
2
没问题,只要它对你有用,如果你能选择我的答案就太好了,你也可以对它进行修改。 - Azhar Ali
1
您无需对UILabel进行子类化,只需使用扩展使UILabel采用该协议即可。 extension UILabel: Hideable {…} - Paulw11
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接