我需要在我的应用中创建一个自定义字段框架。我为字段定义了一个名为FieldType
的协议,并使用它将UITextField
和UIButton
扩展为不同类型的字段。
现在,我想为字段创建一个容器视图,以便容器能够将其字段元素同时引用为UIView
和FieldType
,我想知道是否有一种简洁的方法将它接收的元素类型定义为实现FieldType
协议的特定UIView
?
我可以让FieldContainerView
接受UIView
s或FieldType
s,然后用guard
语句手动检查它是否也与另一个匹配,但感觉有点麻烦。
我尝试了2种方法:
1)定义自定义中介FieldViewType
这个想法是让FieldViewType
直接用FieldType
扩展UIView
,这样对于UITextField: FieldType
和UIButton: FieldType
的一般情况可能是有用的。
protocol FieldType {
var showError: Bool { get set }
var isEmpty: Bool { get set }
}
class CustomTextField: UITextField, FieldType {}
class CustomButtonField: UIButton, FieldType {}
let textField = CustomTextField()
textField is UIView // True
textField is FieldType // True
let buttonField = CustomButtonField()
buttonField is UIView // True
buttonField is FieldType // True
class FieldView: UIView, FieldProtocol {}
let field = FieldView()
field is UIView // True
field is FieldProtocol // True
textField is FieldView // False
buttonField is FieldView // False
2)使用泛型
我可以定义一个泛型类型来满足需求,比如<FieldViewType: UIView where FieldViewType: FieldType>
,但是我不知道在哪里可以最好地解决我的问题。
class FieldContainerView<FieldViewType: UIView where FieldViewType: FieldType>: UIView {
var fields = [FieldViewType]()
func addField(FieldViewType: field) {
fields.append(field)
}
}
我需要为每个要使用的字段类型声明一次容器类,并且不能在同一个容器中使用2个字段类型。
另一种选择是使用addField
在函数级别定义类型约束
class FieldContainerView: UIView {
var fields = [UIView]()
func addField<FieldViewType: UIView where FieldViewType: FieldType>(FieldViewType: field) {
fields.append(field)
}
}
然后在必要的时候将fields
中的每个元素转换为FieldType
,我知道转换总是有效的,因为addField
是向容器添加元素的唯一方法,但这也感觉太麻烦了。
感觉最好的解决方法是能够用typealias
定义FieldViewType
,但似乎不支持这种方法;或者用协议定义UIView
,以便更好地混合,但UIKit不是这样构造的。
2条答案
按热度按时间k97glaaz1#
因此,目前似乎没有办法在属性声明中创建类型约束,我不知道为什么,但我对语言实现一无所知。
我尝试了一种变通方法,其中
FieldType
也有一个view: UIView
属性,该属性具有默认实现。新的
FieldType
声明:这样,在遵循
FieldType
协议之前,您从UIKit层次结构中的哪个类继承都没有关系,只要您在某个地方有UIView
作为超类,您就会有一个可访问的view
属性。这看起来像是一种变通方法,但至少它为同时需要对象的
FieldType
和UIView
属性的集合节省了双重声明。ix0qys7i2#
你能把这一行改一下吗:类字段视图:UI视图,现场协议{}
为此:类FieldView:UI视图,字段类型{}