如何声明扩展特定超类并符合协议的变量

时间:2015-01-15 11:30:04

标签: swift

我想声明一个符合某个协议的视图。一方面,我需要能够指定它是一个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”。我怎样才能做到这一点?如果不可能解决这类问题的推荐方法是什么?

谢谢!

1 个答案:

答案 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;虽然我在评论中提到了这个帖子,但它们不再可编辑了。