我想声明一个符合某个协议的视图。一方面,我需要能够指定它是一个UIView,能够将其添加为子视图,并期望与协议一致。
问题始于,我想为textview创建一个可编辑的通用容器。
我决定使用不同的类 - UILabel不可编辑时和UITextField。所以在我的通用容器中,我希望能够1.将视图添加为子视图,并且2.能够设置文本。
UILabel和UITextField没有用于设置文本的通用接口,因此我让他们使用扩展来实现新协议:
protocol TextView {
var text_:String? {get set}
}
extension UILabel:TextView {
var text_:String? {
get {
return self.text
}
set {
self.text = newValue
}
}
}
extension UITextField: TextView {
var text_:String? {
get {
return self.text
}
set {
self.text = newValue
}
}
}
到目前为止一切顺利 - 但在我的容器视图中,我需要将通用视图声明为UIView 或 TextView。如果我将它作为TextView进行,我必须进行强制转换才能将它们添加为子视图,如果我将其声明为UIView,则必须在我想要设置文本时进行强制转换。
我希望能够指定(编译时)类似“此变量是符合TextView协议的UIView”。我怎样才能做到这一点?如果不可能解决这类问题的推荐方法是什么?
谢谢!
答案 0 :(得分:1)
我得到了答案,感谢Martin R的评论,这比我想象的要简单得多。在我的容器类中,我必须声明类型约束:
class MyContainer<T where T:UIView, T:TextView> {...}
使用要覆盖的方法:
func createValueTextView() -> T {fatalError("must override!")}
然后我可以将我的T实例用作UIView 和一个TextView,这正是我需要的!
然后是具有可编辑字段的容器的子类:
class MyEditableContainer<A>: MyContainer<UITextField> {...}
我覆盖createValueTextView以返回UITextField:
func createValueTextView() -> UITextField {return UITextField()}
同样是不可编辑的:
class MyEditableContainer<A>: MyContainer<UILabel> {...}
func createValueTextView() -> UILabel {return UILabel()}
(请注意,类型参数&#39; A&#39;是&#34;丢弃&#34;参数,当前Swift需要该参数,有关详细信息,请参阅this thread。
此外,最好在TextHolder中重命名TextView或类似的东西,因为协议本身与视图无关。将它作为&#34; TextView&#34;虽然我在评论中提到了这个帖子,但它们不再可编辑了。