Swift协议 - 属性类型子类化

20

我正在定义一个名为PanelController的协议,其中我希望存储一个PanelViewPanelView本身是UIView的子类,定义了面板的基本结构。我有三个不同的视图,它们都是PanelView的子类:LeftPanelMidPanelRightPanel。对于这些面板中的每一个,我都希望定义一个符合PanelController协议的xxxPanelController(左、中、右)。

我遇到的问题在于协议和xxxPanelController

protocol PanelController {
    var panelView: PanelView { get set }
    ...
}

class LeftPanelController: UIViewController, PanelController {
    var panelView = LeftPanelView()
    ...
}

何处

class LeftPanelView: PanelView {
     ...
}

还有一件事...

class PanelView: UIView {
    ...
}

我收到一个错误,提示:LeftPanelController不符合PanelController协议。原因是很显然的:panelView的类型是LeftPanelView而不是PanelView。虽然LeftPanelViewPanelView的子类,但这对我来说似乎非常有限,它应该可以正常工作!但它并没有!

有人能解释一下为什么会这样吗?如果有人能想出解决方法,麻烦告诉我一下!谢谢!


1
它不符合规范,因为协议允许将PanelView的实例分配给LeftPanelView类型的属性。如果在协议中声明该属性为只读,则应该编译。 - Martin R
我假设这个问题以前已经被回答过了,但是在手机上搜索对我来说很困难 :) - Martin R
1个回答

11

问题出在协议中的setter。

假设你想要从LeftPanelController获取panelView。这没问题,因为LeftPanelView可以做PanelView能做的(以及更多)。

但如果你想要设置LeftPanelControllerpanelView,你可以给它任何一个PanelView,因为你将panelView变量定义为LeftPanelView,所以setter有时会失败。

为了解决这个问题,你可以在LeftPanelController中这样做:

var panelView: PanelView = LeftPanelView()
这意味着如果您没有先进行类型转换,就无法访问特定于 LeftPanelView 的任何方法或属性。如果这不是问题,那么这应该可以解决您的问题!

1
你知道一种将类型(例如LeftPanelView)存储在变量中以便稍后用于转换的方法吗?(为了进一步解耦视图和PanelController。) - Clay Ellis
什么是使用案例?如果你需要一个 LeftPanelView 对象,那么你应该存储这种类型的对象。如果你正在使用一个协议,我假设特定类型的对象并不重要。如果确实重要,则协议可能不是合适的解决方案。 - Eric
1
如果 PanelView 是它们都符合的协议,是否适用同样的解释?我遇到了类似的问题,但我的 PanelView 是一个协议。在从基类继承的情况下,你的解释是有道理的,但我很难理解为什么这不适用于协议,因为你关心的只是他们按照协议中定义的方法进行实现。 - blau
是的,解释仍然适用。问题在于控制器认为 panelView 是一个 LeftPanelView 而不是一个 PanelView。这就是为什么显式声明可以解决问题。这有帮助吗? - Eric
12
即使是只读属性,这个问题仍然存在。 - Frederic Adda

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