Swift:属性,它是实现协议的UIView子类

时间:2015-01-06 04:47:23

标签: class swift properties polymorphism protocols

这是场景。我想要显示许多不同的视图,具体取决于我显示用户的模型对象。所以我已经建立了一个协议,可以呈现实现它的任何视图。

class MyItem { /* some model properties */ }

protocol ItemView: class {
    // some protocol methods (e.g. updateWithItem(), etc)
    func setupItem(item: MyItem)
}

class SpecificItemView: UIView, ItemView { /* there will be multiple classes like this */
    func setupItem(item: MyItem) {
        // do item setup
    }
}

class AnotherItemView: UIView, ItemView {
    func setupItem(item: MyItem) {
        // do DIFFERENT item setup
    }
}

然后,当我在视图控制器中使用它们时,我已经获得了一个ItemView类:

class MyViewController: UIViewController {

    var itemView: ItemView? // could be a SpecificItemView or AnotherItemView

    override func viewDidLoad() {
        itemView?.setupItem(MyItem())
        itemView?.removeFromSuperview() /* this line won't compile */
    }
}

除了最后一行之外,一切都有效,我尝试调用UIView方法(removeFromSuperview)。这并不奇怪,因为ItemViewUIView无关。

在Objective C中,我会通过指定我的itemView ivar来解决这个问题:

@property (nonatomic, strong) UIView<ItemView> *itemView;

但我似乎无法为Swift找到类似的语法。我怀疑在Swift中没有办法使用这种模式。如何以Swift友好的方式实现可互换UIView类的总体目标?

到目前为止我找到的一个 hacky 解决方案是将我调用的任何UIView方法(例如removeFromSuperview)添加到我的ItemView协议中

我从Maurice Kelly获得的另一个建议是UIView实现ItemView协议,SpecificItemView和{{1}可以从...下降。你可以看到它implemented in this gist。虽然这解决了在单一类型(例如AnotherItemView)中封装类AND协议的问题,但它基本上使协议毫无意义,因为您现在正在实现父类中的所有协议方法,在子类中重写它们。此解决方案的最大缺点是,当您在View Controller中引用它们时,必须将子类的实例(var itemView: ItemViewParentClass)强制转换为新的hypthetical父类(SpecificItemView)。

4 个答案:

答案 0 :(得分:1)

正如您所发现的,没有办法为对象指定类和协议。

解决问题的最简单方法是在协议中添加removeFromSuperview(以及保证所需的任何其他UIView方法)。

答案 1 :(得分:1)

从Swift 5开始,可以通过将协议限制为仅应用于UIViews来实现这一点。为此,只需执行以下操作:

protocol ItemView: UIView {
  func setupItem(item: MyItem)
}

通过将此约束添加到协议中,迅速编译器识别为ItemView的任何对象也将具有所有UIView方法。

类似地,如果非UIView子类尝试实现ItemView协议,则您的代码将无法编译。

答案 2 :(得分:0)

也许以下(在Swift 4中)可以做到这一点?

class MyViewController: UIViewController {
    typealias T = UIView & ItemView

    var itemView: T?
}

答案 3 :(得分:-1)

ItemView不会延伸UIView,但您的SpecificItemView会延长removeFromSuperView。当然,ItemView上不存在ItemView

在ViewController中,您声明了SpecificItemView类型对象,而不是MyViewController

将您的var itemView:SpecificItemView? 代码更改为:

{{1}}