ios - 在 Swift 中覆盖父类(super class)委托(delegate)

标签 ios swift inheritance delegates overriding

我正在开发一个包含两个 UIView 的 Swift (v1.2) 项目。 MyViewMyViewSubclass

MyView 有一个委托(delegate),我想在 MyViewSubclass 中将其覆盖为一个子协议(protocol),类似于 UITableViews 有一个 UITableViewDelegate 也符合 super UIScrollViewDelegate

我的第一个想法是覆盖父类(super class)属性,但这会导致编译器错误,因为子类无法覆盖具有不同类型的父类(super class)属性。

// 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 ()
}

我的第二个想法是覆盖委托(delegate)属性的隐式 getter 和 setter 方法。子类可以有一个接受 MyViewSubclassDelegate 的 getter,并向下转换为 MyViewDelegate 协议(protocol),因此属性本身不需要被覆盖。

此方法也会导致编译器错误。访问器实际上不能“覆盖”父类(super class)方法,因为它们具有不同的方法签名,并且不能只是声明,因为它们的名称与父类(super class) setter 冲突。

// 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
    }
}

我可以让子类覆盖父类(super class)的 getter 和 setter,并将委托(delegate)存储在一个单独的子类属性中,它确实有效,但是子类看起来应该被分配一个 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 子类用子类型覆盖父类(super class)的属性?

最佳答案

这并不理想,但如果一个协议(protocol)是从另一个协议(protocol)继承的,而不是使用不同的类型,使用相同的类型,但在 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`")
        }
    }
}

虽然不够优雅,但至少您会立即得到一个运行时错误,从而引起程序员的注意。通过包含 /// 注释,它也将显示在快速帮助中。

--

或者,您可以采用更彻底的更改,例如类似于 ABPeoplePickerNavigationControllerdelegatepeoplePickerDelegate 属性,其中子类委托(delegate)是通过不同的属性指定的。

关于ios - 在 Swift 中覆盖父类(super class)委托(delegate),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31839512/

相关文章:

ios - 如何正确旋转 MPMoviePlayerController?

ios - 具有动态高度的 UIWebView 导致内存崩溃

ios - 显示来自 NSMutableString 的特定数据

ios - Swift:在尝试获取 NSDate future 日期时获取 EXC_BAD_INSTRUCTION

ios - VIPER 中 UITableView 委托(delegate)和数据源的实现

c++ - 友元函数中指向基类参数类型的指针

ios - Swift - 通过网络调用和 Storyboard 在 View Controller 中进行依赖注入(inject)?

iOS:如何写入项目中特定目录的文件?

具有返回不同类型的子项的抽象类中的 C# 抽象方法

c# - 跨不同(共享)项目和命名空间的继承