【问题标题】:Overriding a superclass delegate in Swift覆盖 Swift 中的超类委托
【发布时间】:2015-10-28 15:25:19
【问题描述】:

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

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 方法。子类可以有一个获取 MyViewSubclassDelegate 的 getter,并强制转换为 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 子类用子类型覆盖超类的属性?

【问题讨论】:

  • 感谢您的建议!继承协议将起作用(我在示例中这样做),但它仍然会遇到与示例 3 相同的问题,其中子类的委托看起来好像应该是超级协议,其中子协议委托是必需的。现在,我想我会按照你的第一条评论坚持使用两个单独的参数,直到我找到一个更像 UITableViewDelegate 使用的解决方案。
  • @Rob 也许只是我很难。我对该解决方案的主要抱怨是您不能严格执行协议一致性。如果 MyViewSubclass 具有 MyViewDelegate 类型的委托,则无法确保 (delegate as? MyViewSubclassDelegate)?.someOtherFunc() 将永远执行。视图可以被分配超类,而可选链将默默地失败。你也可以检查它是否响应选择器,但是你有一个运行时约束,而不是编译时。

标签: ios swift inheritance delegates overriding


【解决方案1】:

不是很理想,但是如果一个协议是从另一个继承而来的,而不是使用不同的类型,使用相同的类型,但是在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 属性,其中子类委托是通过不同的属性指定的。

【讨论】:

  • 谢谢!到目前为止,这是我能想到的最好的事情!
猜你喜欢
  • 2015-06-26
  • 1970-01-01
  • 1970-01-01
  • 2015-06-20
  • 2014-08-18
  • 1970-01-01
  • 2014-11-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多