我正在开发一个包含两个UIViews的Swift(v1.2)项目。 MyView 和 MyViewSubclass 。
MyView 有一个委托,我想在 MyViewSubclass 中覆盖它作为一个子协议,类似于 UITableViews 如何拥有 UITableViewDelegate ,它也符合超级 UIScrollViewDelegate 。
我的第一个想法是覆盖超类属性,但是这个导致编译器错误,因为子类不能覆盖具有不同类型的超类属性。
// Example throws a compiler error. Can't override property with different type
class MyView : UIView {
weak var delegate : MyViewDelegate?
}
class MyViewSubclass : MyView {
override weak var delegate : MyViewSubclassDelegate? // Compiler error
}
protocol MyViewDelegate {
func someFunc ()
}
protocol MyViewSubclassDelegate : MyViewDelegate {
//func someFunc () Edit: redefinition not necessary, thanks @Rob!
func someOtherFunc ()
}
我的第二个想法是覆盖委托属性的隐式getter和setter方法。子类可以有一个getter,它接受 MyViewSubclassDelegate ,然后转换为 MyViewDelegate 协议,因此不需要重写属性本身。
此方法也会导致编译器错误。访问器实际上不能“覆盖”超类方法,因为它们具有不同的方法签名,并且不能仅因为它们的名称与超类设置器冲突而被声明。
// Example throws a compiler error. Can't declare function with a conflicting name
class MyViewSubclass : MyView {
func setDelegate ( newValue : MyViewSubclassDelegate ) { // Compiler error
super.delegate = newValue as? MyViewDelegate
}
func getDelegate () -> MyViewSubclassDelegate { // Compiler error
return super.delegate as? MyViewSubclassDelegate
}
}
我可以让子类覆盖超类的getter和setter,只需将委托存储在一个单独的子类属性中就可以工作,但是子类看起来应该被分配一个 MyViewDelegate ,当真的需要分配一个 MyViewSubclassDelegate 时,这可能会在将来引起严重的混淆。
// Example works, but it is unclear that MyViewSubclass's delegate should be
// assigned a MyViewSubclassDelegate
class MyViewSubclass : MyView {
private weak var _subclassDelegate : MyViewSubclassDelegate?
override weak var delegate : MyViewDelegate? { // Ambiguous type
didSet {
_subclassDelegate = delegate as? MyViewSubclassDelegate
}
}
}
我知道至少类似的东西是可能的,因为像UITableView和UICollectionView这样的类似乎做我想要的,但它们也是用Objective-C而不是Swift编写的,所以语言允许的细节可能会有所不同
有没有办法让Swift子类用子类型覆盖超类的属性?
答案 0 :(得分:6)
它并不理想,但如果一个协议是从另一个协议继承而不是使用不同的类型,请使用相同的类型,但在didSet
中实现验证:
class MyView : UIView {
/// The `MyViewDelegate` delegate
weak var delegate: MyViewDelegate?
}
class MyViewSubclass: MyView {
/// The `MyViewSubclassDelegate` delegate.
///
/// **Note: This must be MyViewSubclassDelegate**
override weak var delegate: MyViewDelegate? {
didSet {
assert(delegate == nil || delegate is MyViewSubclassDelegate, "The delegate of MyViewSubclass must be of type `MyViewSubclassDelegate`")
}
}
}
它不够优雅,但至少你会立即得到运行时错误,这会将问题带给程序员注意。通过加入///
评论,它也会在快速帮助中显示。
-
或者,您可以采用更激进的更改,例如:类似于delegate
的{{1}}和peoplePickerDelegate
属性,其中子类委托是通过不同的属性指定的。